如何在spring-data-neo4j中更新关系属性?

时间:2013-11-06 12:21:53

标签: java neo4j spring-data-neo4j

我已经构建了一个使用spring-data的项目,并成功创建了实体,添加了与属性的关系。除了更新关系属性值之后,所有内容似乎都运行良好,只有在它们被保留后才会生效。

为了尝试探索它,我合并了SpringData文档中的简单“世界”示例并对其进行了一些改进。 在此示例中,有一个与其他世界相关的World实体。 我在这段关系中添加了一个名为“yearsToReach”的属性。

在我的测试中,我创造了两个世界:火星和地球,并将yearsToReach设置为10。 然后,我调用WorldRepositoryService.updateYearsToOtherWorld并将yearsToReach设置为20.此方法以第一个World的“save”结束,但是当再次查询World时,它似乎实际上并未更改数据库中的值。

也许这很简单,但我花了好几个小时试图弄清楚我做错了什么......

这是我的代码,我删除了一些不相关的部分。 我非常感谢任何响应/代码示例。

这是我的'世界'实体(注意:'BaseWorld'类没有标记为@NodeEntity,它只包含'name'属性。)


    @NodeEntity
    @Getter
    @Setter
    public class World extends BaseWorld {

        @GraphId
        private Long id;

        @RelatedToVia(type = OtherWorldRelationship.RELATIONSHIP_TYPE, direction = Direction.OUTGOING, elementClass = OtherWorldRelationship.class)
        private Set reachableByRocket = new HashSet();


        public void addRocketRouteTo(World otherWorld, int yearsToReach) {
            OtherWorldRelationship otherWorldRelationship = new OtherWorldRelationship();
            otherWorldRelationship.setWorld(this);
            otherWorldRelationship.setOtherWorld(otherWorld);
            otherWorldRelationship.setYearsToReach(yearsToReach);
            reachableByRocket.add(otherWorldRelationship);
        }

        public void updateYearsToOtherWorld(World otherWorld, int years) {
            Iterator otherWorlds = reachableByRocket.iterator();
            while (otherWorlds.hasNext() )
            {
                OtherWorldRelationship otherWorldRelationship = otherWorlds.next();
                if (otherWorld.getName().equals(otherWorldRelationship.getOtherWorld().getName())){
                    otherWorldRelationship.setYearsToReach(years);
                    break;
                }
            }
        }

这是关系类:


    @RelationshipEntity
    @Getter
    @Setter
    public class OtherWorldRelationship {
        public static final String RELATIONSHIP_TYPE = "OtherWorld";

        @GraphId
        Long id;

        @StartNode
        private World world;

        @EndNode
        private World otherWorld;

        private int yearsToReach;

    }

这是WorldRepository接口 - 它只继承自GraphRepository


    public interface WorldRepository extends GraphRepository, NamedIndexRepository {
    }

这是 WorldRepositoryService


    @Repository
    public class WorldRepositoryService implements IWorldRepositoryService {

        @Getter
        @Setter
        @Autowired
        private WorldRepository worldRepository;

        @Override
        @Transactional
        public Collection createSomeWorlds() {
            ArrayList newWorlds = new ArrayList();
            World earth = createWorld("Earth");
            newWorlds.add(earth);

            World mars = createWorld("Mars");
            mars.addRocketRouteTo(earth, 10);
            newWorlds.add(mars);

            return newWorlds;
        }

        @Override
        @Transactional
        public World createWorld(String name) {
            return worldRepository.save(new World(name));
        }

        @Override
        public World findWorldNamed(String name) {
            return worldRepository.findByPropertyValue("name", name);
        }


        @Override
        @Transactional
        public World updateYearsToOtherWorld(World mars, World earth, int years) {
            mars.updateYearsToOtherWorld(earth, years);
            return worldRepository.save(mars);
        }

    }

最后,这些是我测试中的行:


    @Test
        public void testNeo4JRelationshipUpdateData() {

            Iterable worlds = worldRepositoryService.createSomeWorlds();//Mars and Earth

            World earth = worldRepositoryService.findWorldNamed("Earth");
            World mars =  worldRepositoryService.findWorldNamed("Mars");

            Integer distanceInYears = mars.getYearsToOtherWorld(earth);
            System.out.println("Distance beteween Mars and " + distanceInYears);
            Assert.assertEquals(10, distanceInYears.intValue());

            mars = worldRepositoryService.updateYearsToOtherWorld(mars, earth, 20);

            System.out.println("Distance beteween Mars and Earth: " + distanceInYears);
            Assert.assertEquals(20, distanceInYears.intValue());

            mars = worldRepositoryService.findWorldNamed("Mars");
            distanceInYears = mars.getYearsToOtherWorld(earth);
            System.out.println("Distance beteween Mars and Earth after update: " + distanceInYears);

            // !!! This line fails - it gets 10 instead of 20 !!! //
            Assert.assertEquals(20, distanceInYears.intValue());

        }

3 个答案:

答案 0 :(得分:4)

感谢jjaderberg的帮助 - 我为了别人而粘贴了解决方案:

解决方案是保存关系本身而不是保存它的实体。 这是固定代码:

我为关系定义了新的存储库接口:


    public interface OtherWorldRelationshipRepository extends GraphRepository, NamedIndexRepository {

    }

在WorldRepositoryService.clas中,我保存了关系而不是实体:


    @Override
        @Transactional
        public OtherWorldRelationship updateYearsToOtherWorld(World mars, World earth, int years) {
            OtherWorldRelationship yearsToOtherWorldRelation = mars.updateYearsToOtherWorld(earth, years);
            return otherWorldRelationshipRepository.save(yearsToOtherWorldRelation);
        }

就是这样! 希望它可以帮助自己帮助自己。

卡梅尔

答案 1 :(得分:0)

你确定它是最后一个失败的断言吗?似乎第二个应该失败 - 更新后你没有读取distanceInYears变量。

答案 2 :(得分:0)

你完全正确 - 我忘了重读“distanceInYears”。不幸的是,这并没有解决问题......价值仍然是10。 两个断言都失败了(如果我评论第一个,另一个我试图再次检索“火星” - 也失败了。)

正确的测试代码如下所示:


    @Test
        public void testNeo4JRelationshipUpdateData() {

            worldRepositoryService.deleteAll();

            Iterable worlds = worldRepositoryService.createSomeWorlds();//Mars and Earth

            World earth = worldRepositoryService.findWorldNamed("Earth");
            World mars = worldRepositoryService.findWorldNamed("Mars");

            Integer distanceInYears = mars.getYearsToOtherWorld(earth);
            System.out.println("Distance beteween Mars and " + distanceInYears);
            Assert.assertEquals(10, distanceInYears.intValue());

            mars = worldRepositoryService.updateYearsToOtherWorld(mars, earth, 20);
            distanceInYears = mars.getYearsToOtherWorld(earth);

            /* This is the assertion that fails: */
            System.out.println("Distance beteween Mars and Earth: " + distanceInYears);
            Assert.assertEquals(20, distanceInYears.intValue());

            /* This one also fails if we comment the two previous lines: */
            mars = worldRepositoryService.findWorldNamed("Mars");
            distanceInYears = mars.getYearsToOtherWorld(earth);
            System.out.println("Distance beteween Mars and Earth after update: " + distanceInYears);
            Assert.assertEquals(20, distanceInYears.intValue());

        }