cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Cannot create Relationship

Hi,
this is our first Neo4J-Project, so sorry if I'm missing something obvious.

We use Spring Boot 2.6.0 with Spring Data Neo4J 6.2.0 and a remote Neo Aura DB (the free version 4.3.0). I also tested it with a local server (4.3.5 and 4.3.3), this doesn't work either.

I have 2 classes (User, MindMapNode) to which I want to add a Relationship from User to MindMapNode. When using curl, it adds a new Node, but it doesn't add the Relationship. There is no Exception or HTTP-Status Code other than 200 or something logged in the console, nothing.

// imports...
@Node
@Data
@ToString
@Builder
@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
public class User {
    @Id @GeneratedValue private  Long id;

    @Property
    @Getter @Setter @NonNull
    private String username;

    @Getter @Setter
    @Relationship(type = "OWNS", direction = Relationship.Direction.OUTGOING)
    private List<MindMapNode> graphs;

    public void saveGraphForUser(MindMapNode root) {
        if (graphs == null) graphs = new ArrayList<>();
        graphs.add(root);
    }

    public User withId(Long id){
        if (this.getId() == null) {
            return new User(id, this.username, this.password, this.graphs);
        }
        else if (this.getId().equals(id)) {
            return this;
        } else {
            return new User(id, this.username, this.password, this.graphs);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id.equals(user.id) && username.equals(user.username);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username);
    }
}

//imports...
@Node
@AllArgsConstructor
public class MindMapNode {
    @Getter
    @Id @GeneratedValue
    private final Long id;

    @Getter @Setter @NonNull
    private String title;
   // other properties...

    public MindMapNode withId(Long id){
        if (this.getId() == null) {
            return new MindMapNode(id, this.getTitle(), this.getDescription(), this.getWeight(), this.getNeighbors());
        }
        else if (this.getId().equals(id)) {
            return this;
        } else {
            return new MindMapNode(id, this.getTitle(), this.getDescription(), this.getWeight(), this.getNeighbors());
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MindMapNode that = (MindMapNode) o;
        return id.equals(that.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
@Service
public class MindMapNodeService {

    @Autowired
    private MindMapNodeRepository mindMapNodeRepository;
    @Autowired
    private UserService userService;

    public MindMapNode saveMindMap(Long userid, String name) {
        Optional<User> optuser = userService.getUserById(userid);
        if (optuser.isEmpty()) throw new IllegalArgumentException("Userid is not known");
        MindMapNode res = saveMindMapNode(new MindMapRoot("New Title", "", 50, new HashSet<>(), name));
        optuser.get().saveGraphForUser(res);
        return res;
    }
}
//imports...
@RestController
@RequestMapping("/mindmap")
@RequiredArgsConstructor
public class MindMapController {
    @Autowired
    private MindMapNodeService mindMapNodeService;

    @PostMapping("/add")
    public MindMapNode addMindMap(@RequestParam Long userid, @RequestParam String name) {
        return mindMapNodeService.saveMindMap(userid, name);
    }
}

And finally the curl-command:

curl -X POST -F "userid=<id here>" -F "name=newMindMap" http://localhost:8080/mindmap/add

What am I missing?

1 ACCEPTED SOLUTION

Just a wild guess...you are not saving the User.
I can see in the MindMapNodeService:

  1. load user
  2. create and save(? assuming saveMindMapNode does only this) a new MindMapRoot/MindMapNode
  3. add the MindMapNode to the User

But after 3. you have to save the User to persist the change to the collection.
For completeness, you can skip the save of the MindMapNode, just add it to the User and persist it. On save SDN will cascade into all relationships and create the related nodes if needed.
Also you should add a @Transactional around the saveMindMap method to create one logical Spring transaction. If you would keep the code as it is, you might run into a race condition between the transactions of the save of the MindMapNode and the User.

View solution in original post

2 REPLIES 2

Just a wild guess...you are not saving the User.
I can see in the MindMapNodeService:

  1. load user
  2. create and save(? assuming saveMindMapNode does only this) a new MindMapRoot/MindMapNode
  3. add the MindMapNode to the User

But after 3. you have to save the User to persist the change to the collection.
For completeness, you can skip the save of the MindMapNode, just add it to the User and persist it. On save SDN will cascade into all relationships and create the related nodes if needed.
Also you should add a @Transactional around the saveMindMap method to create one logical Spring transaction. If you would keep the code as it is, you might run into a race condition between the transactions of the save of the MindMapNode and the User.

Hi there,

it took a while, but your tip was the right clue 🙂
Adding a userService.saveUser(user) did the trick. We will look at your tip for completeness next and try this out. I also added the @Transactional, but will need to dive a little further into what it actually means.

Thank you!