不要将引用更改为使用cascade="all-delete-orphan"的集合。

10

我遇到一个错误:

在尝试以下操作时,请不要将引用更改为使用cascade="all-delete-orphan"的集合

beginTx();
Parent parent = new Parent();
Child child = new Child();
parent.addChild(child);
getSession().save(parent);
commitTx();
closeSession();

beginTx();
//id is the primary key
child.setID(null);
getSession().update(child);
commitTx();
closeSession();

父子关系为一对多,级联删除设为'all-delete-orphan'。

class Parent {
Set child;
}


<set name="child" table="Child" cascade="all-delete-orphan" inverse="true">
    <key column="FK"></key>
    <one-to-many class="Child"/>
</set>

你有什么想法为什么会抛出这个异常?即使该实体处于分离状态,为什么在主键上设置null会导致此异常?


它是在哪个语句中抛出的?是在这一行 child.setID(null); 吗? - Debojit Saikia
childCategory 是什么?通过调用 child.setID(null);,您想实现什么目标? - Santosh
@debojit:这是因为child.setID(null)的原因。 - user2599052
@user2599052,通过调用child.setID(null);,您是否试图从Child Set中删除特定条目? - Santosh
4个回答

10

如果你加载了一个带有 cascade=all-delete-orphan的集合实体,然后删除对该集合的引用,就会发生这种异常。

不要替换该集合。总是使用 collection.clear() 来删除所有相关的子条目,以便孤儿删除算法可以检测到变化。如果你想要删除某个特定的子项,只需要从集合中将其移除即可。一旦它从集合中移除,它将被视为孤儿并将被删除。


2
但是如果您查看代码片段,我并没有替换集合。我只是在主键上设置了null。 - user2599052
1
这就是为什么我在我的回答中加入了“这个异常通常发生”.. 但是你为什么要在子实体的主键上设置null呢? - Debojit Saikia
2
这怎么可能呢?我假设是这样的,请纠正我如果我错了。使对象瞬态:Hibernate将把它视为一个新的子项,并尝试将其持久化。这与向集合添加新的子项相同。您想使它瞬态,但又不想将其从集合中删除。这就像您想更改持久对象的ID。但是主键的定义表明它不仅唯一而且在行的生命周期内始终保持不变。Hibernate不支持更改标识符值。这可能是此异常的原因。 - Debojit Saikia
通过将其设置为null,它应该是瞬态的,然后Hibernate在插入时会分配一个新的键。而且,这个瞬态对象必须被添加到父对象的集合中,并且实体被分离。这就是上面的代码尝试做的事情。 - user2599052
2
但我还是很困惑!!不管怎样,如果你想要添加新的子元素,创建并添加一个即可。如果你想要更新现有的子元素,只需要更新其属性即可。如果你想要移除一个,只需从集合中移除即可。在commitTx()期间,更改将与数据库进行同步。我不认为需要将持久化对象变为暂态对象,然后再将其添加回集合中。 - Debojit Saikia
显示剩余2条评论

3

对于异常,不要更改级联属性为"all-delete-orphan"的集合引用。您可以使用child.setID(null); 来更改 ID,但会导致异常。

Hibernate使用 PersistentSet 执行异常检查,因此您可以这样做:

child.setID(null);
parent.child=new HashSet(parent.child)

使用HashSet替代PersistentSet


2
那是因为关闭事务并不会关闭当前会话。这意味着child仍然是当前会话的一部分,Hibernate仍将视其为相同的子项,并尝试在数据库上将其id设置为空。
如果您想使child对象成为瞬态对象,应在其上使用evict()

0
另一个可能导致这种情况的原因是,当你使用EntityManager.detach方法将实体图中的对象分离后,紧接着使用EntityManager.flush方法(可能会在稍后执行),此时由于该对象已经从实体图中分离出来,它会尝试重新创建一个新的实体图,但此时它处于一种奇怪的状态,如果你对其进行修改,就会得到以下错误提示:

不要更改集合的引用...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接