我想在hibernate中映射一个树,但由于循环引用(关系不是双向的),持久化它会导致异常。
class Node {
@ManyToOne
Node parent;
@OneToOne
Node leftChild;
@OneToOne
Node rightChild;
}
节点N引用其左子L,后者再次引用N作为其父节点。此外,节点N引用其右子R,其再次再次引用N作为父级。但是,我无法使关系成为双向关系,因为parent将是leftChild和rightChild的反转。使这个模型可以持久化的最佳方法是什么?
此致 约亨
答案 0 :(得分:1)
我没有看到问题:
@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);
}
答案 1 :(得分:0)
在您的示例中,Hibernate无法区分左右孩子。无论Hibernate如何,在数据库中给出两行引用父项,你如何区分左右?因此,如果在同一个表中有多个引用父项的条目,则实际上从父节点到子节点有OneToMany
。因此,我建议您将其建模为@OneToMany
。然后,如果有必要,提供一些瞬态吸气剂,通过一些额外的逻辑区分孩子名单中的左孩子和右孩子。