GT2015
GT2015

Reputation: 85

Updating the target of a simple object relationship with Spring Data Neo4j 4 does not yield the expected result

Just migrated a Spring Data Neo4j 3 project to version 4 (4.0.0.RELEASE, Neo4j 2.2.5 Community Server) and coming up against an issue with a simple one-way object relationship not being updated as expected. This relationship does NOT utilise a RelationshipEntity.

With nodes A, B1 and B2 already in the datastore and an existing relationship A -> B1, changing A's B target node to B2 and saving A gives B1 <- A -> B2. The new relationship is created but the old relationship to B1 is not removed.

expected resulting state :: actual resulting state

A defines a relationship to B, but B does not define a relationship to A (because B to A might end up being one to too many).

...imports omitted

@NodeEntity
public class TypeA {

    @GraphId
    private Long id;

    @Relationship(type = "TYPEB", direction = Relationship.OUTGOING)
    private TypeB b;

    ...getters and setters omitted

}

And B

...imports omitted

@NodeEntity
public class TypeB {

    @GraphId
    private Long id;

    private String identifier;

    public TypeB() {}

    public TypeB(String identifier) {
        this.identifier = identifier;
    }

    ...getters and setters omitted

}

It took a long time to debug this (despite consistent failures in the application) because it seemed impossible to write a failing integration test (running against a real Neo4j server). In fact, I've not been able to write a failing test when the objects A, B1 and B2 are created at test runtime. But when the three nodes and relationship are already present in the datastore when a test is run (the realistic situation when running the application) then a B1 <- A -> B2 outcome is seen. The basic structure of the test is below (complete code can be provided).

// Find the TypeA node
Iterable<TypeA> As = typeARepository.findAll();
TypeA a = Iterables.get(As, 0);

// Find the TypeB node using its String identifier
TypeB b1 = typeBRepository.findByIdentifier(ONE);
assertNotNull(b1);
assertEquals(ONE, b1.getIdentifier());
// check that this is the TypeB node that is related to a
assertEquals(b1.getId(), a.getB().getId());

// Find the other TypeB node using its String identifier
TypeB b2 = typeBRepository.findByIdentifier(TWO);
assertNotNull(b2);
assertEquals(TWO, b2.getIdentifier());

// now create a relationship between a and this TypeB node instead
a.setB(b2);
// and save a
TypeA savedUpdatedA = typeARepository.save(a);

Repositories are created programmatically at test runtime. And using the GraphAware RestTest library to validate the data store subgraph before and after running the repository save calls.

Setting:

<logger name="org.neo4j.ogm" level="DEBUG" />

It can be seen that the Cypher sent to the Neo4j server does not include a delete call for the starting A -> B1 relationship on saving a when the nodes are already present in the datastore. It does when the nodes are created at test runtime. So I'm thinking that there is an issue somewhere around the Neo4jSession whereby the existing relationship is not flagged for deletion - but it is when the same session was used to create the objects in the first place (in the test).

Has anyone had similar issues using or migrating to SDN 4? I cannot recall seeing this with SDN 3. It's not something I looked very hard at, it just seemed to work, but obviously SDN 4 is a complete rewrite.

Upvotes: 3

Views: 581

Answers (1)

Vince
Vince

Reputation: 2181

I believe this is now fixed. You'll need to use the latest snapshot version of the OGM, 1.1.4-SNAPSHOT, rather than the 1.1.3 release.

Upvotes: 0

Related Questions