Spring Data REST Neo4j create a relationship

天大地大妈咪最大 提交于 2019-12-24 00:20:05

问题


I'm building a little test app as a way to learn Angular and refresh myself on a lot of the Spring stack. I have some minor experience with Neo4J, but the app idea has ground with a graph db like Neo4j.

The idea is pretty simple, a ui to create characters and stories, and relate the characters to the stories and each other, map their individual versions of a story and create some graphs that show the character interactions to help write the overall narrative.

I've got nodes for the characters and stories easily enough and the Spring stack is great for giving me rest easy to use rest endpoints for the nodes themselves. But I can't find any concrete examples of creating and maintaining the relationships between those nodes.

For instance, in Cypher, I can relate a character to a story and tell that being's involvement to the story as a relationship property with:

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

Then with the mapping in Spring, the data I get back from the REST endpoint gives me my character and I can follow a link to get the stories that character is a part of. I don't see a way though to post or put to add or remove the character from stories.

I'm also only finding concrete examples in docs from Spring regarding nodes, not really with edges/relationships. Can anyone supply anything like that?

I am fully aware that Neo4J has it's own REST interface, and that is basically what Spring is consuming as well. The main purpose of this exercise is learning some new technology (Angular2/typescript) and refreshing my knowledge of the Spring stack

Thanks!


回答1:


I'm not sure if anyone else has ever found a good or better answer to this, but here is what I had found to work. I have a spring boot project running, I'll post some of the most pertinent code and examples in this answer, but to see the whole REST service project, check https://github.com/jrspriggs/Chronicler

So, the purpose atm for the small app is to create characters/beings that take part in stories, create stories (featuring a title and slug line) and create a relationship between a being and a story with the being's perspective of the story attached to that relationship. This way it collects the various versions of the story from each character.

The neo4j instance is just a basic neo4j instance in Docker/Kitematic on my Windows laptop. Here are the models:

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 (relationship between being to story)

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

From there I have basically the base kind of repository rest resource classes set up for the spring data services. Those take care of the entities, but they fail to really address the relationship for me. What does is to implement a separate rest route to save it

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;

    }   
}

From there, just posting to localhost:3000/beingStory with the following kind of json body will accurately create the relationship:

{
    "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."
}

From that point then, you can walk the relationships from the person to the story. I'll have to add more in the future as I work through this sample app some more to implement the reverse relationship for seeing character involvements from a selected story, and I intend to add relationships between the characters.



来源:https://stackoverflow.com/questions/38571396/spring-data-rest-neo4j-create-a-relationship

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!