Spring Data REST Neo4j创建了一种关系

时间:2016-07-25 15:10:24

标签: neo4j spring-boot spring-data spring-data-neo4j spring-rest

我正在构建一个小测试应用程序,作为学习Angular的方法,并在很多Spring堆栈上刷新自己。我对Neo4J有一些小经验,但应用程序的想法已经基于像Neo4j这样的图形数据库。

这个想法非常简单,可以创建角色和故事,并将角色与故事相互联系起来,映射故事的各个版本,并创建一些图表来展示角色互动,以帮助撰写整体叙事

我已经足够轻松地获得了角色和故事的节点,而Spring堆栈非常适合让我休息,方便节点本身使用休息端点。但我找不到创建和维护这些节点之间关系的任何具体示例。

例如,在Cypher中,我可以将一个角色与一个故事联系起来,并告诉他作为一个关系属性参与故事:

match(p:Being ),(s:Story ) where id(p) = 7 and id(s) = 16 create (p)-[r:TOOK_PART_IN{perspective:"I did not know Mr. Grey better than an acquaintance, though I knew others whom did. They were not made better because of their relationship with him."}]->(s) return r

然后使用Spring中的映射,我从REST端点返回的数据为我提供了我的角色,我可以通过链接获取角色所属的故事。我没有看到发布或添加或删除故事中的角色的方法。

我也只是在Spring的docs中找到关于节点的具体例子,而不是真正的边缘/关系。任何人都可以提供这样的东西吗?

我完全清楚Neo4J拥有自己的REST界面,这基本上也是Spring的用法。这个练习的主要目的是学习一些新技术(Angular2 / typescript)并刷新我对Spring堆栈的了解

谢谢!

1 个答案:

答案 0 :(得分:3)

我不确定是否有其他人找到过这个好的或更好的答案,但这是我找到的工作。我正在运行一个spring boot项目,我将在这个答案中发布一些最相关的代码和示例,但要查看整个REST服务项目,请检查https://github.com/jrspriggs/Chronicler

因此,小应用程序的目的atm是创建参与故事,创建故事(具有标题和slug线)的人物/生物,并创建一个存在与故事之间的关系。关于这种关系的故事的视角。这样,它从每个角色收集故事的各种版本。

neo4j实例只是我的Windows笔记本电脑上Docker / Kitematic中的一个基本neo4j实例。以下是模型:

Being.java:

package com.chronicler.model;

import java.util.Iterator;
import java.util.Set;

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 org.springframework.data.neo4j.annotation.RelatedToVia;
@NodeEntity
public class Being {

    public Long getId() {
        return id;
    }
    @GraphId private Long id;

    private String firstName;
    private String lastName;
    private boolean hero;
    private boolean villain;
    @RelatedToVia(type="TOOK_PART_IN")
    @Fetch private Set<Involvement> involvements;

    public Set<Involvement> getInvolvements() {
        return involvements;
    }
    public void setInvolvements(Set<Involvement> involvements) {
        this.involvements = involvements;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public boolean isHero() {
        return hero;
    }
    public void setHero(boolean hero) {
        this.hero = hero;
    }
    public boolean isVillain() {
        return villain;
    }
    public void setVillain(boolean villain) {
        this.villain = villain;
    }
}

Story.java

package com.chronicler.model;

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

@NodeEntity
public class Story {
    public Long getId() {
        return id;
    }
    @GraphId private Long id;

    private String title;
    private String slug;
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getSlug() {
        return slug;
    }
    public void setSlug(String slug) {
        this.slug = slug;
    }

}

Involvement.java(故事与故事之间的关系)

package com.chronicler.model;

import org.springframework.data.neo4j.annotation.EndNode;
import org.springframework.data.neo4j.annotation.Fetch;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.RelationshipEntity;
import org.springframework.data.neo4j.annotation.StartNode;


@RelationshipEntity(type="TOOK_PART_IN")
public class Involvement {

    @GraphId private Long relationshipId;
    @Fetch @StartNode private Being being;
    @Fetch @EndNode private Story story;
    private String perspective;
    public Long getRelationshipId() {
        return relationshipId;
    }
    public void setRelationshipId(Long relationshipId) {
        this.relationshipId = relationshipId;
    }
    public Being getBeing() {
        return being;
    }
    public void setBeing(Being being) {
        this.being = being;
    }
    public Story getStory() {
        return story;
    }
    public void setStory(Story story) {
        this.story = story;
    }
    public String getPerspective() {
        return perspective;
    }
    public void setPerspective(String perspective) {
        this.perspective = perspective;
    }
}

从那里开始,我基本上为spring数据服务设置了基础类型的存储库休息资源类。那些照顾实体,但他们没有真正解决我的关系。什么是实现单独的休息路线来保存它

BeingController.java:

package com.chronicler;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.chronicler.model.Involvement;
import com.chronicler.repo.InvolvementRepository;

@RestController
public class BeingController {
    @Autowired
    InvolvementRepository involvementRepository;

    @RequestMapping(value="/beingStory", method=RequestMethod.POST)
    public Involvement createBeingStoryRelationship(@RequestBody Involvement involvement) {
        involvementRepository.save(involvement);        
        return involvement;

    }   
}

从那里,只需使用以下类型的json正文发布到localhost:3000 / beingStory将准确地创建关系:

{
    "character": {
        "id": 17,
        "firstName": "Dr. Victor",
        "lastName": "Frankenstein",
        "hero": true,
        "villain": true
      },
    "story": {
        "id": 15,
        "title": "Frankenstein",
        "slug": "A doctor plays god"
      },
  "relationshipId": 10,
    "perspective": "I did a monstrous thing.  I wanted to create life, but I created horrors... such unimaginable horrors, such that mankind has not ever imagined."
}

从那时起,您就可以走出从人到故事的关系。我将来必须添加更多内容,因为我更多地使用此示例应用程序来实现反向关系以查看所选故事中的角色参与,并且我打算在角色之间添加关系。