Announcement Announcement Module
Collapse
No announcement yet.
Best practices for persisting relationships with properties? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Best practices for persisting relationships with properties?

    I'm converting a project from native Neo4j to Spring data and am coming across this dilemma...

    I have two node entities (call them Person) who are connected to each other by a relationship (call it Friendship). When users befriend each other there needs to be certain properties stored with that relationship, namely a creation and expiry date.

    My first idea from the docs and examples was to have my PersonRepository also extend RelationshipOperationsRepository

    public interface PersonRepository extends GraphRepository<Person>, RelationshipOperationsRepository<Person>

    I can then use the createRelationshipBetween method. But what I get would be a plain relationship with no additional properties set on it, i.e. the creation date and expiration date. I really want to populate the relationship POJO before it gets persisted.

    My question would be how to do this - should I use the createRelationshipBetween method, re-retrieve the relationship itself and set some data, so should I instead persist one of the node entities after setting the relationship on it?

    Thanks!

  • #2
    Just to be clear, I'm looking at this page in the documents - http://static.springsource.org/sprin..._relationships.

    Role role = tomHanks.playedIn(forrestGump, "Forrest Gump");

    // either save the actor
    template.save(tomHanks);
    // or the role
    template.save(role);

    // alternative approach
    Role role = template.createRelationshipBetween(actor,movie,
    Role.class, "ACTS_IN");

    With the 'alternative approach', how is that second argument to the Role constructor ("Forrest Gump", the role he played in that film) being persisted. Is it being persisted at all?

    I took a look at the cineasts code on github (from https://github.com/SpringSource/spri...in/User.java):

    public Rating rate(Neo4jOperations template, Movie movie, int stars, String comment) {
    final Rating rating = template.createRelationshipBetween(this, movie, Rating.class, RATED, false).rate(stars, comment);
    return template.save(rating);
    }

    I can see where it's going but it seemed odd having the template being part of the signature of the domain class (I know it's already got the spring data annotations in there).

    Thanks
    Last edited by michaelmc; Jan 18th, 2012, 05:57 PM. Reason: Updating for more detail

    Comment


    • #3
      I know that's one of the limitations of the simple mapping approach - that you need the template for persisting things.

      So you have multiple options:
      Code:
      // number 1
      Friendship friendship = template.createRelationshipBetween(friend1,friend2,
      Friendship.class, "FRIEND");
      friendship.setBeginDate(...);
      
      template.save(friendship);
      
      // number 2
      @RelationshipEntity(type="FRIEND") class Friendship {
         @StartNode Person friend1;
         @EndNode Person friend2;
         Date start;
         Date end;
      }
      
      template.save(new Friendship(person1, person2, start,end));
      
      // number 3
      @NodeEntity class Person {
      
         @RelatedToVia
         Set<Friendship> friends=new HashSet<Friendship>();
      }
      
      person.friends.add(new Friendship(start,end));
      template.save(person);
      For the domain-code with the "template" signature, you're right that is awkward, I just wanted to demonstrate different options.

      You can have this code of course in a service or controller.

      HTH

      Michael

      Comment


      • #4
        Thanks Michael, they all seem like pretty good options to me, did you have a personal preference?

        Presumably I wouldn't actually need the template at all in the third case, if I added the friend in the service layer I could just use the PersonRepository to save it (presumably that uses the template underneath anyway). I guess the two people would need to have been persisted to begin with, in our case I think they are. If not then the service can do this.

        Options 1 and 2 sound like they either require a template, a repository for the friendship, or that the PersonRepository is also a RelationshipOperationsRepostory<Friendship>?

        Thanks for the advice.
        Michael

        Comment


        • #5
          Hmm good question, I think it depends on the use-case.

          The add to set and save the owner is most sensible when creating a large number in one go.

          If you just ocassionally add one and already have a large number the template/repo.createRelationshipBetween() would be preferable as it doesn't have to do delta-detection between the two sets.

          btw. you can of course replace template with repository in most cases, so you don't need both.

          Comment


          • #6
            That definitely makes sense, thank you. I've gone with option 3, but taking the Person and creating the Friendship within the method. It seemed like the most natural in the domain-driven sense (Person.addFriend(Person friend)), but it's good to know that if we run into performance problems there are other options!

            Thanks again!

            Comment

            Working...
            X