2011-04-07 70 views
120

试图更新我的实体时,我有以下问题引用:休眠 - 与级联集合=”全删除,孤儿”不再由所拥有的实体实例

"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; 
} 

我试图清理设置< ..>只,按照这样的:How to "possible" solve the problem,但没有奏效。

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

谢谢!

+0

https://sysdotoutdotprint.wordpress.com/2017/01/25/hibernate-a-collection-with-cascadeall-delete-orphan-was-no-longer-referenced-by-the -owning-entity-instance/ – mel3kings 2017-01-25 13:43:33

+0

@m el3kings,您提供的链接不再有效。 – Opal 2018-02-27 09:32:53

+0

@Opal http://sysdotoutdotprint.com/technologies/java/12 – mel3kings 2018-03-02 09:49:29

回答

13

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

+5

please,一个很好的equals和hashCode方法的例子吗?因为我有很多问题:或者我无法更新我的设置,或者我得到一个StackOverflow错误。我在这里打开一个问题:http://stackoverflow.com/questions/24737145/equals-and-hashcode-of-these-entities-spring-mvc-hibernate。谢谢 – SaganTheBest 2014-07-14 15:36:58

121

检查您将某物分配给sonEntities的所有地点。您引用的链接明确指出创建新的HashSet,但您可以在重新分配该集合时发生此错误。例如:

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

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

要增加孩子:

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

要删除的孩子:

​​
+4

其实,我的问题是关于我的实体的equals和hashcode。遗留代码会带来很多问题,不要忘记检查它。我所做的只是保持删除孤儿策略,正确的equals和hashcode。 – axcdnt 2011-04-10 22:04:59

+2

我很高兴你解决了你的问题。 equals和hashcode已经让我在Hibernate中陷入了几次困境。不要用“[解决]”来更新问题的标题,您应该继续并发布答案,然后将其标记为接受的答案。 – brainimus 2011-04-11 13:47:12

+0

谢谢,我碰到了类似的东西,结果我的setter对于那个Set是空的。 – Siddhartha 2015-02-05 12:30:15

8

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

+0

refresh()完全适合我。谢谢! – Topera 2015-11-27 22:57:18

61

的方法:

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); 
    } 
} 
+1

@Skuld我有一个类似的问题,我应用了你的解决方案(在setter方法中,我清除了子集合this.children.clear() - 并添加了新的子节点this.children.addAll(children))。此更改并未解决我的问题。我仍然得到“具有cascade =”all-delete-orphan的集合“不再被拥有实体实例”异常引用“。你知道为什么吗?非常感谢你! – ovdsrn 2012-12-12 10:42:53

+0

@ovdsrn对不起,这不是我的答案,我只是整理了答案的格式,原作者(kmmanu)可能能够帮助你(或者如果你的情况不同,你可能想开始一个新问题到这里提出的原始问题)祝你好运 – Skuld 2012-12-27 09:48:03

+0

这很好,但是当孩子被包含在一个嵌套的hibernate组件中并且组件在它的Entity中被设为null时,效果并不好。然后你会得到同样的错误。这是因为孩子的所有者是根实体,而不是组成部分是空的......一个这样的组件永远不允许变为空,而是应该导致向前转向destroy()方法孩子...至少,我不知道更好的解决方案...这是一种收集clear()构造,然后在一个组件上通过destroy()... – edbras 2014-07-09 14:47:21

15

当我在冬眠不喜欢你分配到一个集合不同的地方阅读,我认为这样做最安全的事情显然会使其最终是这样的:

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方法,并且它希望它的特殊集合类安装在这里,并且不会接受你的集合类。尽管阅读了所有关于未按照设定的方法分配给您的收藏集的警告,但这让我难倒了一段很长的时间。

所以我改变了这个:

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); 
    } 
} 
} 

这样在第一次通话,休眠安装其专班,并在随后的电话,你可以自己使用的方法不破坏一切。如果你想用你的类作为bean,你可能需要一个工作的setter,并且这至少似乎工作。

+0

你为什么要调用retainAll()?为什么不清除()后跟addAll()? – edbras 2014-07-09 13:26:17

+1

“你为什么要调用retainAll()?为什么不清除()后跟addAll()?”好的问题是,我认为我的工作假设如果在再次添加项目之前没有删除项目,hibernate将不太可能将其视为数据库更新。但我怀疑它不会那样工作。 – user2709454 2015-05-27 23:34:42

+0

您应该在clear()上使用retainAll(),否则如果您恰好传入相同的set对象,则可能会清除角色。例如:user.setRoles(user.getRoles())== user.roles.clear() – marto 2015-11-23 19:45:33

3

HAS关系类型:


不要尝试实例集合,当它在hasMany被声明,只是添加和删除对象。

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

使用关系类型:


但集合可能为空时,才声明为一个属性(使用关系),并在声明中未初始化。

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

我试图用TreeSet当有这个问题。我做初始化oneToManyTreeSet其中工程

@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 更多信息可以here

+0

也许,最好是使用Collections.emptySet()来使用单独的空列表 – ryzhman 2018-01-15 12:24:49

2

我得到这个错误的唯一情况是当我尝试将NULL传递给集合的setter。为了防止这种情况,我的setter方法是这样的:

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

添加我的愚蠢的回答。我们正在使用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 

随着我们创建的关系,它总是打算通过他们自己的回购添加孩子。我还没有添加回购。我们所进行的集成测试通过REST调用正在经历整个实体生命周期,因此事务将在请求之间关闭。孩子没有任何回购意味着json将孩子作为主要结构的一部分,而不是在_embedded中。父母的更新会导致问题。

0

以下解决方案的工作而不是指定新的集合

public void setChildren(Set<ChildEntity> children) { 
    this.children = children; 
} 

所有元素与其他

public void setChildren(Set<ChildEntity> children) { 
    Collections.replaceAll(this.children,children); 
} 
0

@Builder - 使保存Collections.emptyList()即使你说.myCollection(new ArrayList());

@Singular - 忽略一流水平的默认值,并离开现场null即使类字段被声明为myCollection = new ArrayList()

我的2美分,仅仅用了2小时,相同:)

0

一个原因更换可能会使用龙目岛的我

//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; 
相关问题