我有以下自表映射:
public class Node implements {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "IDFATHER", referencedColumnName = "ID")
private Node father;
@OneToMany(mappedBy = "father", fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
@Cascade(value =
{
CascadeType.ALL,
CascadeType.DELETE_ORPHAN
})
private List<Node> children;
基本上它是使用相同表的经典父/子节点树,其中IDFATHER列指向父节点的id。
我在树上实现了一些基本操作:
实施操作2)单删除:
// father of the node to be deleted
Node father = deletedNode.getFather();
if (deletedNode.getChildCount() != 0)
{
List<eNode> tempChildren = new ArrayList<Node>();
// put all children of deleted node in a temp list because the
// new FOR loop doesn't allow concurrent modification while looping
for (Node child : deletedNode.getChildren())
{
tempChildren.add(child);
}
for (Node child : tempChildren)
{
// re-attach first all the children to the father
father.getChildren().add(child);
child.setFather(father);
// remove all the children from the deleted node list
deletedNode.getChildren().remove(child);
// remove the deleted node from the father children' list
father.getChildren().remove(deletedNode);
}
}
this.nodeDAO.flush();
我得到了例外
javax.persistence.EntityNotFoundException:传递给已删除的实体 坚持
据我所知,根据官方文档,当您使用Cascade.ALL
删除实体时,删除会与其子项级联。但是在这种特殊情况下,所有孩子都重新加入父亲,所以不应该删除他们......
当我删除Cascade.DELETE_ORPHAN
时,它可以正常工作。从逻辑上讲,通过将孩子重新附加到父亲身上,他们不再孤儿,所以Cascade.DELETE_ORPHAN
真的不重要。
关于这个问题的任何线索?
答案 0 :(得分:1)
最后,我通过查看源代码找到了这种行为的原因:
假设我们有一个父亲N0,一个孩子N1,它有自己的孩子N2。
操作是:
在flush()期间,调用以下代码:
org.hibernate.collection.PersistentBag
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
List sn = (List) snapshot;
return getOrphans( sn, bag, entityName, getSession() );
}
org.hibernate.collection.AbstractPersistentCollection
protected static Collection getOrphans(
Collection oldElements,
Collection currentElements,
String entityName,
SessionImplementor session)
throws HibernateException {
// short-circuit(s)
if ( currentElements.size()==0 ) return oldElements; // no new elements, the old list contains only Orphans
if ( oldElements.size()==0) return oldElements; // no old elements, so no Orphans neither
...
...
实际上,当为节点 N1 输入方法getOrphans()时, oldElements 集合包含 N2 和 currentElements 收集是空的。根据代码,Hibernate认为现在所有的孩子都是孤儿,它不会检查他们是否属于新的父母。
解决方案将如Ryan所说:
答案 1 :(得分:0)
“删除孤立”仅表示从集合中删除的对象被删除。它没有考虑对象是否被添加到另一个集合。该标志实际上与集合相关联,而不是与单个对象相关联。您的经验与此一致,javax.persistence.OneToMany.orphanRemoval的描述也是如此,顺便说一下,它取代了CascadeType.DELETE_ORPHAN。后者现已弃用。