spring neo4j spring-data-neo4j-4 neo4j-ogm

spring - Transacciones y entidades de relación mapeando problemas con Neo4j OGM



spring-data-neo4j-4 neo4j-ogm (2)

Versiones utilizadas: spring-data-neo4j 4.2.0-BUILD-SNAPSHOT / neo4j-ogm 2.0.6-SNAPSHOT

Tengo problemas para obtener correctamente las entidades de relación .

Las siguientes llamadas de recuperación no devuelven resultados consistentes (ejecutados en la misma transacción):

  1. session.query ("MATCH (: A) - [b: HAS_B] - (: C) CUENTA DEVUELTO (b) como conteo") devuelve 1
  2. session.query ("MATCH (: A) - [b: HAS_B] - (: C) RETORNO b") devuelve correctamente la entidad de relación como un objeto RelationshipModel
  3. session.query (B.class, "MATCH (: A) - [b: HAS_B] - (: C) RETORNO b") devuelve nulo!

Observación importante: cuando todas las operaciones (crear, captar) se realizan en la misma transacción, parece estar bien.

He podido implementar una solución mediante el uso de session.query (String, Map) para consultar la entidad de relación y asignarla yo mismo a mi 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); } }


Esta consulta session.query(B.class, "MATCH (:A)-[b:HAS_B]-(:C) RETURN b") devuelve solo la relación, pero no el nodo de inicio o nodo final, por lo que el OGM no puede hidratar esta . Siempre debe devolver el nodo de inicio y final junto con la relación como session.query(B.class, "MATCH (a:A)-[b:HAS_B]-(c:C) RETURN a,b,c")

La razón por la que parece funcionar cuando ambos crean y recuperan datos en la misma transacción es porque la sesión ya tiene una copia en caché de a c y, por lo tanto, b puede hidratarse con nodos de inicio y final en caché.


En primer lugar, actualice de OGM 2.0.6-SNAPSHOT a 2.1.0-SNAPSHOT. He notado algo de comportamiento impropio en el primero que podría ser una parte del problema.

Ahora a tu prueba. Aquí hay varias cosas que vale la pena investigar.

  • Uso de @DirtiesContext : Parece que no estás tocando el contexto y si lo usas para restablecer el contexto entre las pruebas para que obtengas una nueva sesión / transacción, eso va por el camino equivocado. Simplemente use @Transactional en @Transactional lugar. El corredor de Spring JUnit tratará esto de una manera especial (ver el siguiente punto).
  • Consciente de que las pruebas transaccionales se retrotraen automáticamente: Jasper tiene razón. Las pruebas de integración de primavera siempre se retrotraerán por defecto . Si quiere asegurarse de que su prueba JUnit se compromete , tendrá que @Commit it . Un buen ejemplo de cómo configurar su prueba se puede ver aquí .
  • Saber cómo funcionan los proxies de transacciones de primavera. Además de toda esta confusión, debe asegurarse de no llamar simplemente al método transaccional al método transaccional en la misma clase y esperar que se aplique el comportamiento transaccional de Spring. Una rápida redacción de por qué se puede ver aquí .

Si abordas esos problemas, todo debería estar bien.