Hibernate – cascade =“all-delete-orphan”的集合不再被拥有的实体实例引用

尝试更新我的实体时出现以下问题:

"A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance". 

我有一个父实体,它有一些子实体的集合。 当我尝试更新它时,我将所有引用设置为此集合并进行设置。

以下代码代表我的映射:

 @OneToMany(mappedBy = "parentEntity", fetch = FetchType.EAGER) @Cascade({ CascadeType.ALL, CascadeType.DELETE_ORPHAN }) public Set<ChildEntity> getChildren() { return this.children; } 

我试着只清理Set <..>,根据这个: 如何“可能”解决这个问题,但没有奏效。

如果您有任何想法,请让我知道。

谢谢!

检查所有分配给sonEntities的地方。 你引用的链接明确指出创build一个新的HashSet,但是你可以在你重新分配集合的时候出现这个错误。 例如:

 public void setChildren(Set<SonEntity> aSet) { this.sonEntities = aSet; //This will override the set that Hibernate is tracking. } 

通常你只想在构造函数中一次“新build”这个集合。 任何时候你想添加或删除列表中的东西,你必须修改列表的内容,而不是分配一个新的列表。

要添加孩子:

 public void addChild(SonEntity aSon) { this.sonEntities.add(aSon); } 

要删除孩子:

 public void removeChild(SonEntity aSon) { this.sonEntities.remove(aSon); } 

非常感谢答案…

方法

 public void setChildren(Set<SonEntity> aSet) { this.sonEntities = aSet; } 

如果parentEntity被分离,并且如果我们更新,则工作。
但是,如果实体不是从每个上下文中分离的,(即查找和更新操作在同一个事务中),则下面的方法工作。

 public void setChildren(Set<SonEntity> aSet) { //this.sonEntities = aSet; //This will override the set that Hibernate is tracking. this.sonEntities.clear(); if (aSet != null) { this.sonEntities.addAll(aSet); } } 

当我在各个地方读到hibernate不喜欢你分配到一个集合时,我认为最安全的事情显然是使它最终这样:

 class User { private final Set<Role> roles = new HashSet<>(); public void setRoles(Set<Role> roles) { this.roles.retainAll(roles); this.roles.addAll(roles); } } 

然而,这是行不通的,你得到了可怕的“不再引用”的错误,这实际上是在这种情况下相当误导。

事实certificate,hibernate调用你的setRoles方法,并希望它的特殊集合类安装在这里,并不会接受你的集合类。 尽pipe阅读了所有关于不按照设定的方法分配给你的collections集的警告,但这让我难以忍受。

所以我改变了这个:

 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,至less这似乎工作。

其实,我的问题是关于我的实体的equals和hashcode。 遗留代码可能带来很多问题,不要忘记检查一下。 我所做的只是保持删除孤儿的战略,正确的等号和哈希码。

我有同样的错误。 对我来说问题是,在保存实体后,映射的集合仍然是空的,当试图更新实体时抛出exception。 对我有什么帮助:保存实体,然后进行刷新(集合不再为空),然后执行更新。 也许使用新的ArrayList()或者其他东西初始化集合也可能会有所帮助。

有关系types:


hasMany声明集合时,不要尝试实例化集合,只需添加和删除对象。

 class Parent { static hasMany = [childs:Child] } 

使用关系types:


但是,只有当声明为属性(使用关系)并且不在声明中初始化时,集合才可以为null。

 class Parent { List<Child> childs = [] } 

尝试使用TreeSet时遇到此问题。 我用TreeSet初始化了oneToMany

 @OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true) @OrderBy("id") private Set<WizardAnswer> answers = new TreeSet<WizardAnswer>(); 

但是,这会带来上述question描述的错误。 所以看来, hibernate支持SortedSet ,如果只是改变上面的行

 @OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval=true) @OrderBy("id") private SortedSet<WizardAnswer> answers; 

它的作品像魔术:)更多关于hibernate SortedSet信息可以在这里

唯一一次我得到这个错误是当我尝试将NULL传递给setter的集合。 为了防止这种情况,我的制定者看起来像这样:

 public void setSubmittedForms(Set<SubmittedFormEntity> submittedForms) { if(submittedForms == null) { this.submittedForms.clear(); } else { this.submittedForms = submittedForms; } } 

添加我愚蠢的答案。 我们正在使用Spring Data Rest。 这是我们相当标准的关系。 该模式在别处使用。

 //Parent class @OneToMany(mappedBy = 'parent', cascade= CascadeType.ALL, orphanRemoval = true) @LazyCollection(LazyCollectionOption.FALSE) List<Child> children = new LinkedList<>() //Child class @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = 'ParentID', updatable = false) @JsonBackReference Parent parent 

随着我们创build的关系,一直打算通过自己的回购添加孩子。 我还没有添加回购。 我们所做的集成testing是通过REST调用通过实体的一个完整的生命周期,以便事务在请求之间closures。 没有孩子的回购意味着json把孩子们作为主要结构的一部分,而不是_embedded 。 父母的更新会导致问题。

以下解决scheme为我工作

 //Parent class @OneToMany(mappedBy = 'parent', cascade= CascadeType.ALL, orphanRemoval = true) @OrderBy(value="ordinal ASC") List<Child> children = new ArrayList<>() //Updated setter of children public void setChildren(List<Children> children) { this.children.addAll(children); for (Children child: children) child.setParent(this); } //Child class @ManyToOne @JoinColumn(name="Parent_ID") private Parent parent;