Spring Data Neo4j和实体在集合和其他实体中是@RelatedTo - 未创建关系

时间:2014-07-20 16:48:22

标签: neo4j spring-data-neo4j

今天我在与SDN和我的模特挣扎。

基本上我想要实现的是Foo实体与Bar实体的关系,但我还需要在每个nextBar实体中保持Bar关系,以便轻松检查一些nextBarBar s的属性已订购)。

我想通过使用:

来实现这一目标
package neo4j.example.domain;

import org.springframework.data.neo4j.annotation.Fetch;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;

import java.util.HashSet;
import java.util.Set;

@NodeEntity
public class Foo {

    @GraphId
    public Long id;

    @Fetch
    @RelatedTo
    public Set<Bar> bars = new HashSet<>();

    @Override
    public String toString() {
        return "Foo{" +
                "id=" + id +
                ", bars=" + bars +
                '}';
    }
}

package neo4j.example.domain;

import org.springframework.data.neo4j.annotation.Fetch;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelatedTo;

@NodeEntity
public class Bar {

    @GraphId
    public Long id;

    @Fetch
    @RelatedTo
    public Bar nextBar;

    @Override
    public String toString() {
        return "Bar{" +
                "id=" + id +
                ", nextBar=" + nextBar +
                '}';
    }
}

但我在项目单元测试中遇到了问题(其中一些没有通过)。经过一番调查后,我发现如果我一次性坚持数据:

public class AllInOneTest {
    ApplicationContext context = new AnnotationConfigApplicationContext(ExampleNeo4jConfiguration.class);
    GraphDatabaseService graphDatabaseService = context.getBean(GraphDatabaseService.class);
    Neo4jOperations neo4jOperations = context.getBean(Neo4jOperations.class);
    FooRepository fooRepository = context.getBean(FooRepository.class);
    ExecutionEngine executionEngine = new ExecutionEngine(graphDatabaseService);

    @Before
    public void setUp(){
        executionEngine.execute(CLEAN_DATABASE_QUERY);
    }

    @Test
    public void shouldProperlyCreateRelationships(){
        // given
        Bar firstBar = new Bar();
        Bar secondBar = new Bar();
        Foo foo = new Foo();

        firstBar.nextBar = secondBar;
        foo.bars.addAll(Arrays.asList(firstBar, secondBar));

        // when
        fooRepository.save(foo);

        // then
        Foo retrievedFoo = fooRepository.findOne(foo.id);
        System.out.println(retrievedFoo);
        for(Bar bar: retrievedFoo.bars) {
            if(firstBar.id.equals(bar.id)){
                Assert.assertNotNull(bar.nextBar);
            }
        }
    }
}

我得到了

Foo{id=0, bars=[Bar{id=2, nextBar=Bar{id=1, nextBar=null}}, Bar{id=1, nextBar=null}]}

来自我的System.out.println所以一切都按照我想要的方式持续存在。

但通常我不是一次性获得所有Bar(用户添加一个Bar,5分钟后用户添加第二个Bar) - 这就是问题。

package neo4j.example;

import neo4j.example.configuration.ExampleNeo4jConfiguration;
import neo4j.example.domain.Bar;
import neo4j.example.domain.Foo;
import neo4j.example.repository.FooRepository;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.graphdb.GraphDatabaseService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

import static neo4j.example.repository.Query.CLEAN_DATABASE_QUERY;

public class OneByOneTest {
    ApplicationContext context = new AnnotationConfigApplicationContext(ExampleNeo4jConfiguration.class);
    GraphDatabaseService graphDatabaseService = context.getBean(GraphDatabaseService.class);
    FooRepository fooRepository = context.getBean(FooRepository.class);
    ExecutionEngine executionEngine = new ExecutionEngine(graphDatabaseService);

    @Before
    public void setUp(){
        executionEngine.execute(CLEAN_DATABASE_QUERY);
    }

    @Test
    public void shouldProperlyCreateRelationships(){
        // given
        Bar firstBar = new Bar();
        Foo foo = new Foo();

        foo.bars.add(firstBar);
        fooRepository.save(foo);

        // when
        Bar secondBar = new Bar();
        Foo firstRetrievedFoo = fooRepository.findOne(foo.id);
        Bar[] bars = firstRetrievedFoo.bars.toArray(new Bar[0]);
        bars[0].nextBar = secondBar;
        firstRetrievedFoo.bars.add(secondBar);

        System.out.println(firstRetrievedFoo);
        fooRepository.save(firstRetrievedFoo);
        System.out.println(firstRetrievedFoo);

        // then
        // then
        Foo retrievedFoo = fooRepository.findOne(foo.id);
        System.out.println(retrievedFoo);
        for(Bar bar: retrievedFoo.bars) {
            if(firstBar.id.equals(bar.id)){
                Assert.assertNotNull(bar.nextBar);
            }
        }
    }
}

空数据库上的此代码打印:

Foo{id=125130, bars=[Bar{id=125131, nextBar=Bar{id=null, nextBar=null}}, Bar{id=null, nextBar=null}]}
Foo{id=125130, bars=[Bar{id=125131, nextBar=Bar{id=125132, nextBar=null}}, Bar{id=125132, nextBar=null}]}
Foo{id=125130, bars=[Bar{id=125132, nextBar=null}, Bar{id=125131, nextBar=null}]}

测试失败。我可以看到,在保持与新nextBar的关系之前和之后指向我想要的地方。从存储库中检索Foo后,它将设置为null。

以下是示例项目:https://github.com/Adebski/neo4j-relatedto-problem/

我正在使用Neo4j的简单映射和嵌入版本。高级映射目前不适合我,因为我的正常项目位于Scala SBT,而AFAIK此组合与SDN高级映射不起作用。

1 个答案:

答案 0 :(得分:0)

尝试单独发出save(firstBar)(在设置nextBar之后),看看是否有帮助?可能是级联保存并不像你想象的那样工作 - 也就是说我知道它会坚持任何超然的实体,但如果它没有更新所有属性/关系,我不会感到惊讶已存在的节点。一般来说,如果我没记错,@ RelatedTo只检索连接节点的id,除非它用@Fetch注释。因此,我不认为它可以很容易地确定您是否添加了关系,或者更改了属性。