Hibernate 中的循环关系

发布于 2024-11-25 15:23:54 字数 333 浏览 1 评论 0原文

我想在休眠中映射一棵树,但由于循环引用(关系不是双向的)而持久化它会导致异常。

class Node {
    @ManyToOne
    Node parent;

    @OneToOne
    Node leftChild;

    @OneToOne
    Node rightChild;
}

节点 N 引用其左子节点 L,后者又再次引用 N 作为其父节点。此外,节点 N 引用其右子节点 R,而右子节点 R 又再次将 N 引用为父节点。但是,我无法使关系成为双向的,因为父级将是左子级和右子级的相反。使该模型持久的最佳方法是什么?

问候, 约亨

I want to map a tree in hibernate, but persisting it results in an exception because of the cyclic reference (the relationships are not bidirectional).

class Node {
    @ManyToOne
    Node parent;

    @OneToOne
    Node leftChild;

    @OneToOne
    Node rightChild;
}

Node N references its left child L which in turn references N again as its parent. Also, node N references its right child R which in turn again references N again as parent. However, I cannot make the relationships bidirectional, because parent would be the inverse of both leftChild and rightChild. What is the best way to make this model persistable?

Regards,
Jochen

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

时光匆匆的小流年 2024-12-02 15:23:54

我没有看到问题:

@Entity
class Node {
    @Id @GeneratedValue
    private int id;
    private String name;

    @ManyToOne(cascade = CascadeType.ALL)
    Node parent;

    @OneToOne(cascade = CascadeType.ALL)
    Node leftChild;

    @OneToOne(cascade = CascadeType.ALL)
    Node rightChild;

    Node() {}

    public Node(String name) {
        this.name = name;
    }
    // omitted getters and setters for brevity
}

public static void main(String[] args) {
    SessionFactory sessionFactory = new Configuration()
                  .addAnnotatedClass(Node.class)
                  .setProperty("hibernate.connection.url",
                      "jdbc:h2:mem:foo;DB_CLOSE_DELAY=-1")
                  .setProperty("hibernate.hbm2ddl.auto", "create")
                  .buildSessionFactory();
    Session session = sessionFactory.openSession();
    Transaction transaction = session.beginTransaction();
    Node a = new Node("A");
    Node b = new Node("B");
    Node c = new Node("C");
    Node d = new Node("D");
    Node e = new Node("E");
    a.setLeftChild(b);
    b.setParent(a);
    a.setRightChild(c);
    c.setParent(a);
    b.setLeftChild(d);
    d.setParent(b);
    b.setRightChild(e);
    e.setParent(b);
    System.out.println("Before saving:");
    print(a, 1);
    Serializable rootNodeId = session.save(a);
    transaction.commit();
    session.close();

    session = sessionFactory.openSession();
    Node root = (Node) session.load(Node.class, rootNodeId);
    System.out.println("Freshly loaded:");
    print(root, 1);
    session.close();
}

private static void print(Node node, int depth) {
    if (node == null) { return; }
    System.out.format("%" + depth + "s\n", node);
    print(node.getLeftChild(), depth + 1);
    print(node.getRightChild(), depth + 1);
}

I don't see the problem:

@Entity
class Node {
    @Id @GeneratedValue
    private int id;
    private String name;

    @ManyToOne(cascade = CascadeType.ALL)
    Node parent;

    @OneToOne(cascade = CascadeType.ALL)
    Node leftChild;

    @OneToOne(cascade = CascadeType.ALL)
    Node rightChild;

    Node() {}

    public Node(String name) {
        this.name = name;
    }
    // omitted getters and setters for brevity
}

public static void main(String[] args) {
    SessionFactory sessionFactory = new Configuration()
                  .addAnnotatedClass(Node.class)
                  .setProperty("hibernate.connection.url",
                      "jdbc:h2:mem:foo;DB_CLOSE_DELAY=-1")
                  .setProperty("hibernate.hbm2ddl.auto", "create")
                  .buildSessionFactory();
    Session session = sessionFactory.openSession();
    Transaction transaction = session.beginTransaction();
    Node a = new Node("A");
    Node b = new Node("B");
    Node c = new Node("C");
    Node d = new Node("D");
    Node e = new Node("E");
    a.setLeftChild(b);
    b.setParent(a);
    a.setRightChild(c);
    c.setParent(a);
    b.setLeftChild(d);
    d.setParent(b);
    b.setRightChild(e);
    e.setParent(b);
    System.out.println("Before saving:");
    print(a, 1);
    Serializable rootNodeId = session.save(a);
    transaction.commit();
    session.close();

    session = sessionFactory.openSession();
    Node root = (Node) session.load(Node.class, rootNodeId);
    System.out.println("Freshly loaded:");
    print(root, 1);
    session.close();
}

private static void print(Node node, int depth) {
    if (node == null) { return; }
    System.out.format("%" + depth + "s\n", node);
    print(node.getLeftChild(), depth + 1);
    print(node.getRightChild(), depth + 1);
}
寄风 2024-12-02 15:23:54

在你的例子中,Hibernate 无法区分左右孩子。无论 Hibernate 如何,给定数据库中引用父级的两行,如何区分左行和右行?因此,如果同一个表中有多个引用父节点的条目,则实际上有从父节点到子节点的 OneToMany。因此,我建议您将其建模为 @OneToMany。然后,如果有必要,提供一些瞬态 getter,通过一些额外的逻辑来区分子列表中的左子元素和右子元素。

There is no way for Hibernate to distinguish left and right child in your example. Regardless of Hibernate, given two rows in the database that have reference to parent, how do you distinguish left and right? So, if you have multiple entries in the same table that refer to parent, you are actually having OneToMany from parent to children nodes. Therefore, I recommend that you model it as @OneToMany. Then, if necessary, provide some transient getters that will distinguish left child vs right child in the list of children via some additional logic.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文