Announcement Announcement Module
Collapse
No announcement yet.
neo4j - Inheritance with RelationshipEntities Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • neo4j - Inheritance with RelationshipEntities

    Hi,

    I'm trying to get RelationshipEntities which inherit from a common base class working and have run into an issue. I've pasted below a sample representation of the domain I'm working with and a sample test case showing where I'm having a problem. I'm testing with these classes by adding them to the current cineasts sample project and adding my test case to the existing DomainTest class. I'm using simple mapping (non-aspects).

    Any hints would be greatly appreciated!

    Code:
    package org.neo4j.cineasts.domain.test;
    
    import org.springframework.data.neo4j.annotation.GraphId;
    import org.springframework.data.neo4j.annotation.NodeEntity;
    
    @NodeEntity
    public class BasicEntity {
        @GraphId
        private Long entityId;
    
        /* lots of other common properties here in our real domain */
    
        public BasicEntity() {
        }
    
        public Long getEntityId() {
            return entityId;
        }
    }
    Code:
    package org.neo4j.cineasts.domain.test;
    
    import org.springframework.data.neo4j.annotation.*;
    
    @RelationshipEntity
    public class BasicRelationship {
        @GraphId
        private Long entityId;
    
        @Fetch
        @StartNode
        private BasicEntity startNode;
    
        @Fetch
        @EndNode
        private BasicEntity endNode;
    
        /* lots of other common properties here in our real domain */
    
        public BasicRelationship() {
        }
    
        public BasicRelationship(Long entityId, BasicEntity startNode, BasicEntity endNode) {
            this.entityId = entityId;
            this.startNode = startNode;
            this.endNode = endNode;
        }
    }
    Code:
    package org.neo4j.cineasts.domain.test;
    
    import org.springframework.data.neo4j.annotation.Fetch;
    import org.springframework.data.neo4j.annotation.RelatedToVia;
    
    import java.util.Set;
    
    public class Project extends BasicEntity {
    
        @Fetch
        @RelatedToVia
        private Set<ProjectDetailRelationship> projectDetailRelationships;
    
        public Set<ProjectDetailRelationship> getProjectDetailRelationships() {
            return projectDetailRelationships;
        }
    }
    Code:
    package org.neo4j.cineasts.domain.test;
    
    import org.neo4j.graphdb.Direction;
    import org.springframework.data.neo4j.annotation.Fetch;
    import org.springframework.data.neo4j.annotation.RelatedTo;
    
    public class ProjectDetail extends BasicEntity {
        private String name;
    
        @Fetch
        @RelatedTo(type = ProjectDetailRelationship.TYPE, direction = Direction.INCOMING)
        private Project parentProject;
    
        public ProjectDetail() {
        }
    
        public ProjectDetail(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public Project getParentProject() {
            return parentProject;
        }
    }
    Code:
    package org.neo4j.cineasts.domain.test;
    
    import org.springframework.data.neo4j.annotation.RelationshipType;
    
    public class ProjectDetailRelationship extends BasicRelationship {
        public static final String TYPE = "PROJECT_HAS_PROJECT_DETAIL";
    
        @RelationshipType
        private String type = TYPE;
    
        public ProjectDetailRelationship() {
        }
    
        public ProjectDetailRelationship(Long entityId, Project project, ProjectDetail projectDetail) {
            super(entityId, project, projectDetail);
        }
    }
    Code:
    //Added to org.neo4j.cineasts.domain.DomainTest
        @Test
        public void testInheritanceDomain() {
            final String validName = "FOO";
    
            GraphRepository<Project> projectRepository = template.repositoryFor(Project.class);
            GraphRepository<ProjectDetail> projectDetailRepository = template.repositoryFor(ProjectDetail.class);
    
            Project project = new Project();
            project = projectRepository.save(project);
    
            ProjectDetail projectDetail = new ProjectDetail(validName);
            projectDetailRepository.save(projectDetail);
    
            ProjectDetailRelationship projectDetailRelationship = new ProjectDetailRelationship(null, project, projectDetail);
            template.save(projectDetailRelationship);
    
            project.getProjectDetailRelationships().add(projectDetailRelationship);
            project = projectRepository.save(project);
    
            assertEquals(1, count(projectRepository.findAll()));
            assertEquals(1, count(projectDetailRepository.findAll()));
    
            ProjectDetail actualProjectDetail = projectDetailRepository.findAll().iterator().next();
            assertEquals(validName, actualProjectDetail.getName());
            assertEquals(project.getEntityId(), actualProjectDetail.getParentProject().getEntityId());
    
            //all tests above pass without issue -- the test below fails: expected:<1> but was:<0>
            Project actualProject = projectRepository.findOne(project.getEntityId());
            assertEquals(1, actualProject.getProjectDetailRelationships().size());
        }
    
        private int count(Iterable iterable) {
            int count = 0;
            for (Object object : iterable) {
                count++;
            }
            return count;
        }

  • #2
    Could you quickly explain what you want to do? The semantics of the use-case.

    Michael

    Comment


    • #3
      Hi Michael,

      I'm trying to setup a model to track the history of edits made to a project over time. In my real domain the BasicRelationship is actually more like a BasicHistoryTrackingRelationship and has attributes on it for beginDate, endDate, createdBy, ... When a new Project is created a new ProjectDetail is also created with a ProjectDetailRelationship tying it back to the parent Project. The beginDate on the new ProjectDetailRelationship gets set to the current time and the endDate is set to null.

      Whenever a change is made to an attribute in the ProjectDetail a new ProjectDetail is created with a ProjectDetailRelationship tying it back to the parent Project and the endDate of the previous ProjectDetailRelationship gets set to the current time. There are a bunch of other relationships that hang off of the Project too -- like ProjectStaffing with a ProjectStaffingRelationship, ProjectFinancials with a ProjectFinancialsRelationship, ...

      To get the current representation of a Project we just get the Project and all of its relationships that have a null end date -- and to get the representation for a specific effective date we look for relationships with begin and end dates that are before and after the effective date.

      I'd like to have all of those RelationshipEntities extend from the common BasicHistoryTrackingRelationship since they all have the same attributes on them but cant seem to get it to work quite right.

      Thanks,

      --Jesse

      Comment


      • #4
        Anyone have any suggestions on how to get this type of inheritance working with SDN?

        Comment


        • #5
          Jesse,

          thanks for your patience, this was a bit tricky to find out, there was one error in SDN and I moved the relationship-type to the @RelationshipEntity. I took the liberty of adding your tests to SDN to make sure it works now.

          Michael

          https://jira.springsource.org/browse/DATAGRAPH-213

          Comment


          • #6
            Hi Michael,

            That's great news -- thanks very much!

            --Jesse

            Comment


            • #7
              For completeness, this has been fixed in SDN, but the code above is a bit of a red herring: it is generally impossible to map dynamic relationship types back from Neo4j. So the example above has this in it:

              Code:
              @RelationshipType
              String type = "myDynamicRelationshipType;
              That should be changed to use either default or annotation-provided relationship types in order to be able to map them back: http://spring.neo4j.org/docs#referen...typeprecedence

              Or, of course, you could write a Cypher query to fetch these relationships again.

              Regards,

              Lasse

              Comment

              Working...
              X