当 StartNode 和 EndNode 是同一类型的对象时,Neo4j OGM RelationshipEntity

Neo4j OGM RelationshipEntity when StartNode and EndNode are objects of same type

我正在关注 Neo4j OGM 指南 - http://neo4j.com/docs/ogm/java/stable/

对于关系实体,我们需要有一个开始节点和一个结束节点。我稍微修改了这个例子(让它像这样更简单)-

@NodeEntity
public class Student extends Entity {
    private String name;

    @Relationship(type= "ENROLLED")
    private Enrollment enrollment = new Enrollment();

    public String getName() {
        return name;
    }

    public Enrollment getEnrollment() {
        return enrollment;
    }

    public void setEnrollment(Enrollment enrollment) {
        this.enrollment = enrollment;
    }

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }
}

@NodeEntity
public class Course extends Entity {
    private String name;

    public String getName() {
        return name;
    }

    @Relationship(type= "ENROLLED", direction= Relationship.INCOMING)
    private Enrollment enrollment = new Enrollment();

    public Enrollment getEnrollment() {
        return enrollment;
    }

    public void setEnrollment(Enrollment enrollment) {
        this.enrollment = enrollment;
    }

    public Course() {
    }

    public Course(String name) {
        this.name = name;
    }
}

@RelationshipEntity(type = "ENROLLED")
public class Enrollment extends Entity {
    @StartNode
    private Student student;

    @EndNode
    private Course course;

    private Date enrolledDate;

    public Student getStudent() {
        return student;
    }

    public Course getCourse() {
        return course;
    }

    public Date getEnrolledDate() {
        return enrolledDate;
    }

    public Enrollment() {
    }

    public Enrollment(Student student, Course course, Date enrolledDate) {
        this.student = student;
        this.course = course;
        this.enrolledDate = enrolledDate;
    }
}

现在,当我尝试在 Neo4j 中保存它时,它工作正常。但是在我的场景中,StartNode 和 EndNode 对象的类型是相同的 -

@NodeEntity
public class MyObject extends Entity {
    private String name;

    @Relationship(type="CONNECTION")
    private MyConnection startConnection = new MyConnection();

    @Relationship(type="CONNECTION", direction= Relationship.INCOMING)
    private MyConnection endConnection = new MyConnection();

    public String getName() {
        return name;
    }

    public MyConnection getStartConnection() {
        return startConnection;
    }

    public void setStartConnection(MyConnection myConnection) {
        this.startConnection = myConnection;
    }

    public MyConnection getEndConnection() {
        return endConnection;
    }

    public void setEndConnection(MyConnection endConnection) {
        this.endConnection = endConnection;
    }

    public MyObject() {
        super();
    }

    public MyObject(String name) {
        super();
        this.name = name;
    }
}

@RelationshipEntity(type="CONNECTION")
public class MyConnection extends Entity {
    @StartNode
    private MyObject start;

    @EndNode
    private MyObject end;

    private String name;

    public String getName() {
        return name;
    }

    public MyConnection() {
        super();
    }

    public MyConnection(MyObject start, MyObject end, String name) {
        super();
        this.start = start;
        this.end = end;
        this.name = name;
    }
}

当我尝试使用 -

保存这些内容时
public class Main {

    public static void main(String[] args) {
        Session session = Neo4jSessionFactory.getInstance().getNeo4jSession();

        Student s = new Student("manoj");
        Course c = new Course("physics");
        Enrollment e = new Enrollment(s, c, new Date());
        s.setEnrollment(e);
        c.setEnrollment(e);

        MyObject startObj = new MyObject("Start Object");
        MyObject endObj = new MyObject("End Object");
        MyConnection conn = new MyConnection(startObj, endObj, "Connection");
        startObj.setStartConnection(conn);
        endObj.setEndConnection(conn);

        try(Transaction tx = session.beginTransaction()) {
            session.save(s);
            session.save(c);
            session.save(e);

            session.save(startObj);
            session.save(endObj);
            session.save(conn);

            tx.commit();
        }
    }
}

学生、课程和注册对象被保存,但是两个 MyObject 和 MyConnection 对象没有被保存,我得到以下异常 -

Exception in thread "main" java.lang.NullPointerException
    at org.neo4j.ogm.metadata.MetaData.classInfo(MetaData.java:76)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapRelationshipEntity(EntityGraphMapper.java:389)
    at org.neo4j.ogm.mapper.EntityGraphMapper.link(EntityGraphMapper.java:319)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:262)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntity(EntityGraphMapper.java:154)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapRelatedEntity(EntityGraphMapper.java:528)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapRelationshipEntity(EntityGraphMapper.java:420)
    at org.neo4j.ogm.mapper.EntityGraphMapper.link(EntityGraphMapper.java:319)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:262)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntity(EntityGraphMapper.java:154)
    at org.neo4j.ogm.mapper.EntityGraphMapper.map(EntityGraphMapper.java:87)
    at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:65)
    at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:41)
    at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:370)
    at neo4j.ogm.ex.Main.main(Main.java:37)

你能帮我解决这个问题吗 - 1) StartNode 和 EndNode 对象是否必须是不同类型的? 2) 我的代码有问题还是 Neo4j OGM 的缺点?

提前致谢,

马诺杰。

尝试 Luanne 的建议后更新 -

谢谢卢安妮。我尝试了你的建议,尽管我不得不以不同的方式指定 URL。我用了 - http://m2.neo4j.org/content/repositories/snapshots 因为默认情况下它使用 https 并且我遇到了一些安全异常并且没有下载此依赖项。

无论如何,使用 1.1.1-SNAPSHOT 版本,我仍然得到以下错误 -

Exception in thread "main" java.lang.NullPointerException
    at org.neo4j.ogm.metadata.MetaData.classInfo(MetaData.java:80)
    at org.neo4j.ogm.mapper.EntityGraphMapper.haveRelationEndsChanged(EntityGraphMapper.java:391)
    at org.neo4j.ogm.mapper.EntityGraphMapper.getRelationshipBuilder(EntityGraphMapper.java:362)
    at org.neo4j.ogm.mapper.EntityGraphMapper.link(EntityGraphMapper.java:325)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:276)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntity(EntityGraphMapper.java:157)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapRelatedEntity(EntityGraphMapper.java:571)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapRelationshipEntity(EntityGraphMapper.java:473)
    at org.neo4j.ogm.mapper.EntityGraphMapper.link(EntityGraphMapper.java:329)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:276)
    at org.neo4j.ogm.mapper.EntityGraphMapper.mapEntity(EntityGraphMapper.java:157)
    at org.neo4j.ogm.mapper.EntityGraphMapper.map(EntityGraphMapper.java:90)
    at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:67)
    at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:43)
    at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:376)
    at neo4j.ogm.ex.Main.main(Main.java:37)

您是否打算将 MyObject 建模为包含单个传出关系类型 CONNECTION 和单个传入关系类型 CONNECTION,其中每个关系都有一个 属性 name?

因此,如果我们查看 EndObject,那么 startConnection 是与名称 conn2 的关系,而 endConnection 是与名称 conn1 的关系?

如果是这样,我们这里可能有问题。 https://jira.spring.io/browse/DATAGRAPH-728

更新: 这毕竟不是错误。问题是你在 MyObject:

中的初始化
@Relationship(type="CONNECTION")
private MyConnection startConnection = new MyConnection();

@Relationship(type="CONNECTION", direction= Relationship.INCOMING)
private MyConnection endConnection = new MyConnection();

您已将 startConnectionendConnection 初始化为一个无效的关系实体,即没有开始和结束节点的实体。

在您的测试中,您将 startConnection 设置为 startObj 而不是结束。实际上,endConnection 由无效关系实体表示。

删除初始化,它应该会如您所愿地工作。

感谢 Luanne 的回答/建议。我看到了您的优秀文章 The essence of Spring Data Neo4j 4 并意识到我的需求与成分配对示例(在您的文章中提到)非常相似。对我来说,两个对象 (MyObject) 之间可以有一个连接 (MyConnection)。所以我修改后的代码是这样的 -

package neo4j.ogm.ex.domain;

import java.util.HashSet;
import java.util.Set;

import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;

@NodeEntity
public class MyObject extends Entity {
    private String name;

    @Relationship(type="CONNECTION", direction= Relationship.UNDIRECTED)
    private Set<MyConnection> connections = new HashSet<>();

    public String getName() {
        return name;
    }

    public Set<MyConnection> getConnections() {
        return connections;
    }

    public void addConnection(MyConnection myConnection) {
        myConnection.getStart().getConnections().add(myConnection);
        myConnection.getEnd().getConnections().add(myConnection);
    }

    public MyObject() {
        super();
    }

    public MyObject(String name) {
        super();
        this.name = name;
    }
}

package neo4j.ogm.ex.domain;

import org.neo4j.ogm.annotation.EndNode;
import org.neo4j.ogm.annotation.RelationshipEntity;
import org.neo4j.ogm.annotation.StartNode;

@RelationshipEntity(type="CONNECTION")
public class MyConnection extends Entity {
    @StartNode
    private MyObject start;

    @EndNode
    private MyObject end;

    private String name;

    public String getName() {
        return name;
    }

    public MyObject getStart() {
        return start;
    }

    public MyObject getEnd() {
        return end;
    }

    public MyConnection() {
        super();
    }

    public MyConnection(MyObject start, MyObject end, String name) {
        super();
        this.start = start;
        this.end = end;
        this.name = name;
    }
}

而且效果很好。我还将尝试您提出的删除无效初始化的其他建议。

再次感谢,

马诺杰。