Versions used: spring-data-neo4j 4.2.0-BUILD-SNAPSHOT / neo4j-ogm 2.0.6-SNAPSHOT
I'm having problems to correctly fetch relationship entities.
The following fetch calls don't return consistent results (executed in the same transaction):
Important remark: When all operations (create, fetch) are done in the same transaction, it seems to be fine.
I have been able to implement a workaround by using session.query(String, Map) to query the relationship entity and map it by myself into my POJO.
@NodeEntity
public class A {
public A () {}
public A (String name) {
this.name = name;
}
@GraphId
private Long graphId;
private String name;
@Relationship(type="HAS_B", direction=Relationship.OUTGOING)
private B b;
}
@RelationshipEntity(type="HAS_B")
public class B {
public B () {}
public B (String name, A a, C c) {
this.name = name;
this.a = a;
this.c = c;
}
@GraphId
private Long graphId;
@StartNode
private A a;
@EndNode
private C c;
private String name;
}
@NodeEntity
public class C {
public C () {}
public C (String name) {
this.name = name;
}
@GraphId
private Long graphId;
private String name;
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={MyTest.TestConfiguration.class})
public class MyTest {
@Autowired
private MyBean myBean;
@Configuration
@EnableAutoConfiguration
@EnableTransactionManagement
@EnableNeo4jRepositories("com.nagra.ml.sp.cpm.core.repositories")
public static class TestConfiguration {
@Bean
public org.neo4j.ogm.config.Configuration configuration() {
org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
config.driverConfiguration().setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver");
return config;
}
@Bean
public SessionFactory sessionFactory() {
return new SessionFactory(configuration(), "com.nagra.ml.sp.cpm.model");
}
@Bean
public Neo4jTransactionManager transactionManager() {
return new Neo4jTransactionManager(sessionFactory());
}
@Bean
public MyBean myBean() {
return new MyBean();
}
}
@Test
public void alwaysFails() {
myBean.delete();
myBean.create("1");
try { Thread.sleep(2000); } catch (InterruptedException e) {} //useless
myBean.check("1"); // FAILS HERE !
}
@Test
public void ok() {
myBean.delete();
myBean.createAndCheck("2");
}
}
@Transactional(propagation = Propagation.REQUIRED)
public class MyBean {
@Autowired
private Session neo4jSession;
public void delete() {
neo4jSession.query("MATCH (n) DETACH DELETE n", new HashMap<>());
}
public void create(String suffix) {
C c = new C("c"+suffix);
neo4jSession.save(c);
A a = new A("a"+suffix);
neo4jSession.save(a);
B bRel = new B("b"+suffix, a, c);
neo4jSession.save(bRel);
}
public void check(String suffix) {
//neo4jSession.clear(); //Not working even with this
Number countBRels = (Number) neo4jSession.query("MATCH (:A)-[b:HAS_B]-(:C) WHERE b.name = 'b"+suffix+"' RETURN count(b) as count", new HashMap<>()).iterator().next().get("count");
assertEquals(1, countBRels.intValue()); // OK
Iterable<B> bRels = neo4jSession.query(B.class, "MATCH (:A)-[b:HAS_B]-(:C) WHERE b.name = 'b"+suffix+"' RETURN b", new HashMap<>());
boolean relationshipFound = bRels.iterator().hasNext();
assertTrue(relationshipFound); // FAILS HERE !
}
public void createAndCheck(String suffix) {
create(suffix);
check(suffix);
}
}
This query session.query(B.class, "MATCH (:A)-[b:HAS_B]-(:C) RETURN b")
returns only the relationship but not the start node or end node and so the OGM cannot hydrate this. You need to always return the start and end node along with the relationship like session.query(B.class, "MATCH (a:A)-[b:HAS_B]-(c:C) RETURN a,b,c")
The reason it appears to work when you both create and fetch data in the same transaction is that the session already has a cached copy of a
and c
and hence b
can be hydrated with cached start and end nodes.