我有以下问题时,试图更新我的实体:
"A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance".
我有一个父实体,它有一个Set<…>的子实体。当我尝试更新它时,我得到了要设置到这个集合的所有引用并设置它。
下面的代码表示我的映射:
@OneToMany(mappedBy = "parentEntity", fetch = FetchType.EAGER)
@Cascade({ CascadeType.ALL, CascadeType.DELETE_ORPHAN })
public Set<ChildEntity> getChildren() {
return this.children;
}
我已经尝试清理Set<..只有>,根据这个:如何“可能”解决问题,但它没有工作。
如果你有什么想法,请告诉我。
谢谢!
有一个类似的bug: https://hibernate.atlassian.net/browse/HHH-9940。
以及复制它的代码:https://github.com/abenneke/sandbox/tree/master/hibernate-null-collection/src/test
有2个可能的解决方案:
集合初始化为空集合(而不是null)
orphanRemoval设置为false
例如- was:
@OneToMany(cascade = CascadeType.REMOVE,
mappedBy = "jobEntity", orphanRemoval = true)
private List<JobExecutionEntity> jobExecutionEntities;
变成:
@OneToMany(cascade = CascadeType.REMOVE,
mappedBy = "jobEntity")
private List<JobExecutionEntity> jobExecutionEntities;
当我在很多地方读到hibernate不喜欢你给一个集合赋值时,我认为最安全的做法显然是让它像这样成为final:
class User {
private final Set<Role> roles = new HashSet<>();
public void setRoles(Set<Role> roles) {
this.roles.retainAll(roles);
this.roles.addAll(roles);
}
}
然而,这不起作用,您会得到可怕的“不再引用”错误,在这种情况下,这实际上是相当具有误导性的。
结果是hibernate调用setRoles方法,并且它希望在这里安装它的特殊集合类,并且不接受您的集合类。尽管阅读了所有关于不要在set方法中给集合赋值的警告,我还是被这个问题难住了很长一段时间。
所以我改成了这个:
public class User {
private Set<Role> roles = null;
public void setRoles(Set<Role> roles) {
if (this.roles == null) {
this.roles = roles;
} else {
this.roles.retainAll(roles);
this.roles.addAll(roles);
}
}
}
因此,在第一次调用时,hibernate安装它的特殊类,在随后的调用中,您可以自己使用该方法,而不会破坏任何东西。如果希望将类用作bean,则可能需要一个可工作的setter,这至少看起来是可行的。