3

To work with a neo4j-graphdatabase standalone server i add the dependency of SDN 4.0.0.RC1 to my pom:

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-neo4j</artifactId>
        <version>4.0.0.RC1</version>
        <exclusions>
            <exclusion>
                <groupId>org.neo4j.app</groupId>
                <artifactId>neo4j-server</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

In my application i want to manage families. Persons as NodeEntities, relationtypes as NodeEntities and family-relationships as RelationshipEntities.

To save nodes or relationships i use repository.save(T t) (repository extends GraphRepository<T>). This works for all nodes, but not for relationships.

The explicit not working code:

    Relation createdRelation = new Relation(typeName, from, to, getCurrentUsername());
    createdRelation.setBegin(begin);
    createdRelation.setEnd(end);
    Relation relation = relationRepository.save(createdRelation);

I get an Relation-Object back from save(T t). But the RelationshipEntity is not persisted in the graphdatabase. Also my Relation-Object does not have any id.

The RelationshipEntity class looks like this:

@RelationshipEntity(type = "RELATION")
public class Relation extends BaseMutableGraphEntity {

@Property
private String type;

@StartNode
private Person fromPerson;

@EndNode
private Person toPerson;

private Relation() {
}

...getters and setters...}

The graph-id is saved in the BaseClass:

public abstract class BaseGraphEntity implements AuditEntity {

@GraphId
private Long id;

...with getters and setters...}

My question now is:

How can i save my RelationshipEntities with Spring Data Neo4j 4 RC1?

Is there an other repository for RelationshipEntities?

P.S.: I tried to change the place of my graph-id to the main RelationshipEntity, but it does not work.

mzober
  • 91
  • 7

3 Answers3

2

I have also encountered this quirk and was able to persist my relationships by:

  • Setting your relationship on the @StartNode entity
  • Saving the @StartNode entity OR the @RelationshipEntity, it seems the key is that the object has to be set on the @StartNode first

So in your example, you would have to do something like:

Relation createdRelation = new Relation(typeName, from, to, getCurrentUsername());
createdRelation.setBegin(begin);
createdRelation.setEnd(end);
begin.setRelation(createdRelation);
Relation relation = relationRepository.save(createdRelation);

That all said I have to confess that I'm not 100% sure if this is the way it is meant to be done as it is not clear in the current docs revision BUT it does seem to be the approach taken in the SDN4 example tests: https://github.com/spring-projects/spring-data-neo4j/blob/4.0.x/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/examples/movies/MoviesIntegrationTest.java (see findOneShouldConsiderTheEntityType)

simonl
  • 1,240
  • 7
  • 19
  • Thank you, this solves the problem. But unfortunately i cannot use my RelationshipRepository... And my 2 Persons are "from" and "to", but i know what you mean with your post. – mzober Jul 21 '15 at 14:42
  • Ok gotcha; I actually have tested it and have been able to get `RelationshipRepository.save` to work as well, the quirk being that you have to add your relationship to the "from" object first. Once you do that, saving either the relationship or the "from" object should work. – simonl Jul 21 '15 at 14:53
  • It really depends on the object graph being navigable as you'd expect in the physical graph. I've added an explanation. – Luanne Jul 21 '15 at 16:03
2

What you're seeing is the fact that the object graph (your domain model) does not correspond to the actual graph you expect.

Relation createdRelation = new Relation(typeName, from, to, getCurrentUsername());
    createdRelation.setBegin(begin);
    createdRelation.setEnd(end);
    Relation relation = relationRepository.save(createdRelation);

Here, the relationship entity correctly represents the relationship with a start node and an end node. Now if you attempt to navigate this "object graph" to the start entity i.e. begin you'll find that you cannot navigate via the relationship to the end entity end.

When entities are persisted, the object graph is traversed to determine what is new or modified and persist those. In this case, when traversal reaches your start node, it finds no relationships to other nodes, and effectively, this relationship which should have been created, is not.

Simon's code works because he's made the entity graph consistent with the physical graph. Then you can save either the entity at the end or the relationship entity itself.

If you think in terms of your objects like a graph, this will all fall into place.

Luanne
  • 19,145
  • 1
  • 39
  • 51
  • "Begin" and "end" are optional date-properties of my relationship. "From" and "to" are the two connected persons. – mzober Jul 22 '15 at 08:50
0

This is the code that solves my problem, thank you simonl!

Relation relation = new Relation(typeName, from, to, getCurrentUsername());
relation.setBegin(begin);
relation.setEnd(end);
from.addOutgoingRelation(relation);
personRepository.save(from);
return createResponseBuilder.build(relation);

... i change my code to

Relation relation = new Relation(typeName, from, to, getCurrentUsername());
relation.setBegin(begin);
relation.setEnd(end);
from.addOutgoingRelation(relation);
return createResponseBuilder.build(relationRepository.save(relation));

because of Luannes comment, thank you too!

mzober
  • 91
  • 7