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;