事务和关系实体映射Neo4j OGM的问题

时间:2016-10-04 08:51:58

标签: spring neo4j spring-data-neo4j-4 neo4j-ogm

使用的版本:spring-data-neo4j 4.2.0-BUILD-SNAPSHOT / neo4j-ogm 2.0.6-SNAPSHOT

我有问题才能正确获取关系实体

以下提取调用不会返回一致的结果(在同一事务中执行):

  1. session.query(“MATCH(:A) - [b:HAS_B] - (:C)RETURN count(b)as count”)返回1
  2. session.query(“MATCH(:A) - [b:HAS_B] - (:C)RETURN b”)正确返回关系实体作为RelationshipModel对象
  3. session.query(B.class,“MATCH(:A) - [b:HAS_B] - (:C)RETURN b”)返回null!
  4. 重要提示:当所有操作(创建,获取)都在同一个事务中完成时,它似乎没问题。

    我已经能够通过使用session.query(String,Map)查询关系实体并将其自己映射到我的POJO 来实现解决方法。< / p>

    @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);
        }
    }
    

2 个答案:

答案 0 :(得分:4)

此查询session.query(B.class, "MATCH (:A)-[b:HAS_B]-(:C) RETURN b")仅返回关系,但不返回起始节点或结束节点,因此OGM无法对此进行补充。您需要始终返回开始和结束节点以及session.query(B.class, "MATCH (a:A)-[b:HAS_B]-(c:C) RETURN a,b,c")

之类的关系

当您在同一事务中创建和获取数据时,它似乎有效的原因是会话已经有ac的缓存副本,因此b可以是用缓存的开始和结束节点加水。

答案 1 :(得分:0)

首先,请从OGM 2.0.6-SNAPSHOT升级到2.1.0-SNAPSHOT。我注意到前者的一些违规行为可能是问题的一部分。

现在进行测试。这里有几件事情值得研究。

  • 使用@DirtiesContext:您似乎无法触及上下文,如果您正在使用它来重置测试之间的上下文,那么您将获得一个新的会话/交易然后关于它是错误的方式。只需使用@Transactional代替。 Spring JUnit运行器将以特殊方式对待它(参见下一点)。
  • 意识到Transactional测试会自动回滚:Jasper是对的。 Spring集成测试将always roll back by default。如果您想确保JUnit测试提交then you will have to @Commit it。可以看到如何设置测试的一个很好的示例here
  • 了解Spring Transaction代理的工作原理。除了所有这些混乱之外,您还必须确保不要在同一个类中调用事务方法的事务方法,并期望应用Spring的Transactional行为。快速写下为什么可以看到here

如果你解决这些问题,一切都应该没问题。