3

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.

GT2015
  • 85
  • 4
  • This appears to be a bug. I have raised a ticket for it: https://github.com/neo4j/neo4j-ogm/issues/74 – Vince Oct 21 '15 at 11:05
  • Vince, thank you for getting back to me so quickly, identifying the bug and raising the issue. Your test case is similar to mine but considerably more elegant!! – GT2015 Oct 21 '15 at 12:12
  • np :) Should be fixed now, please see the answer below. – Vince Oct 21 '15 at 16:11
  • We have come across a number of issues which are seemingly to do with how Neo4jSession manages/caches relationships, most of which we haven't been able to reproduce in a test (using InProcessServer) and they also can't be reproduced consistently in a real Neo4jServer. For example, at one point the server gets into a state where making any changes to a node would revert all previously added/removed relationships for a second node, but restarting the server resolves the issue. It also appears that these issues are more likely to occur in a concurrency situation. – user1838830 Oct 22 '15 at 02:33
  • Here's one issue where OGM seems to cache deleted relationships until server restarts: https://jira.spring.io/browse/DATAGRAPH-777 – user1838830 Oct 22 '15 at 02:34
  • @user1838830 - This is extremely unlikely to be a bug in the Spring Data part of the project, much more likely a defect in the underlying OGM itself. Accordingly I've raised a new ticket for it here: https://github.com/neo4j/neo4j-ogm/issues/76, and updated your JIRA to refer to this ticket. Please track progress against this ticket, rather than the JIRA. – Vince Oct 23 '15 at 08:53

1 Answers1

0

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.

Vince
  • 2,181
  • 13
  • 16
  • Vince, great turnaround time on that one! Checked out that snapshot and my test now passes - new relationship created, old relationship deleted. Thank you again. – GT2015 Oct 22 '15 at 11:19