我在尝试更新我的实体时遇到以下问题:
"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 <..>,根据这个:How to "possible" solve the problem但它没有用。
如果您有任何想法,请告诉我。
谢谢!
检查您为sonEntities分配内容的所有地方。您引用的链接明确指出创建一个新的HashSet,但您可以在重新分配该集时随时出现此错误。例如:
public void setChildren(Set<SonEntity> aSet)
{
this.sonEntities = aSet; //This will override the set that Hibernate is tracking.
}
通常,您只想在构造函数中“设置”一次“新”。每当您想要添加或删除列表中的内容时,您必须修改列表的内容而不是分配新列表。
要添加孩子:
public void addChild(SonEntity aSon)
{
this.sonEntities.add(aSon);
}
要删除孩子:
public void removeChild(SonEntity aSon)
{
this.sonEntities.remove(aSon);
}
@OneToMany(mappedBy = 'parent', cascade= CascadeType.ALL, orphanRemoval = true)
List<Child> children = new ArrayList<>()
当我将子对象添加到现有的子对象列表时,我遇到了同样的错误。
childService.saveOrUpdate(child);
parent.addToChildren(child);
parentService.saveOrUpdate(parent);
解决我的问题是:child = childService.saveOrUpdate(child);
现在,孩子也恢复了其他细节,并且工作正常。
加上我愚蠢的答案。我们正在使用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
。对父母的更新会导致问题。
以下解决方案为我工作
//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;
而不是分配新的集合
public void setChildren(Set<ChildEntity> children) {
this.children = children;
}
替换所有元素
public void setChildren(Set<ChildEntity> children) {
Collections.replaceAll(this.children,children);
}
另一个原因可能是使用lombok。
@Builder
- 即使你说Collections.emptyList()
,也能保存.myCollection(new ArrayList());
@Singular
- 忽略类级默认值并离开字段null
,即使类字段被声明为myCollection = new ArrayList()
我的2美分,只花了2个小时与相同:)
当我设置A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance
时,我得到了parent.setChildren(new ArrayList<>())
。当我改为parent.getChildren().clear()
时,它解决了这个问题。
小心
BeanUtils.copyProperties(newInsum, insumOld,"code");
这种方法打破了休眠。
我正在使用Spring Boot,虽然没有直接覆盖它,但是我还是将这个问题与一个集合有关,因为我使用custom serializer and deserializer为同一个集合声明了一个额外的字段,以便提供更加前端友好的数据表示:
public List<Attribute> getAttributes() {
return attributes;
}
public void setAttributes(List<Attribute> attributes) {
this.attributes = attributes;
}
@JsonSerialize(using = AttributeSerializer.class)
public List<Attribute> getAttributesList() {
return attributes;
}
@JsonDeserialize(using = AttributeDeserializer.class)
public void setAttributesList(List<Attribute> attributes) {
this.attributes = attributes;
}
似乎即使我自己没有覆盖该集合,反序列化也会在引擎盖下完成,同时触发此问题。解决方案是更改与反序列化器关联的setter,以便清除列表并添加所有内容,而不是覆盖它:
@JsonDeserialize(using = AttributeDeserializer.class)
public void setAttributesList(List<Attribute> attributes) {
this.attributes.clear();
this.attributes.addAll(attributes);
}
它可能是由hibernate-enhance-maven-plugin
引起的。当我启用enableLazyInitialization
属性时,这个异常开始在我的懒惰集合上发生。我正在使用hibernate 5.2.17.Final。
注意这两个休眠问题:
我和Spring Boot完全不同!对我而言,这不是因为设置了收集属性。
在我的测试中,我试图创建一个实体,并为另一个未使用的集合收到此错误!
经过这么多的尝试,我只是在测试方法上添加了一个@Transactional
并解决了它。不过没有原因。
方法:
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);
}
}
我在使用JSON post请求更新实体时遇到了这个问题。当我更新实体而没有关于子项的数据时,即使没有子项,也会发生错误。添加
"children": [],
到请求机构解决了问题。
当我在各种地方读到hibernate不喜欢你分配给一个集合时,我认为最安全的做法显然是让它最终像这样:
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,这至少似乎有效。
实际上,我的问题是关于我的实体的equals和hashcode。遗留代码可能带来很多问题,永远不要忘记检查它。我所做的只是保持delete-orphan策略并纠正equals和hashcode。
我有同样的错误。对我来说问题是,在保存实体之后,映射的集合仍然为null,并且在尝试更新实体时抛出了异常。什么对我有帮助:保存实体,然后进行刷新(集合不再为空),然后执行更新。也许使用新的ArrayList()或其他东西初始化集合也可能有所帮助。
有关系类型:
当它在hasMany
中声明时,不要尝试实例化该集合,只需添加和删除对象。
class Parent {
static hasMany = [childs:Child]
}
使用关系类型:
但是,只有当声明为属性(使用关系)并且未在声明中初始化时,该集合才可以为null。
class Parent {
List<Child> childs = []
}
我试图使用TreeSet
时遇到了这个问题。我确实用oneToMany
初始化TreeSet
@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
我使用@ user2709454方法进行了小改进。
public class User {
private Set<Role> roles;
public void setRoles(Set<Role> roles) {
if (this.roles == null) {
this.roles = roles;
} else if(this.roles != roles) { // not the same instance, in other case we can get ConcurrentModificationException from hibernate AbstractPersistentCollection
this.roles.clear();
if(roles != null){
this.roles.addAll(roles);
}
}
}
}
我遇到此错误的唯一一次是当我尝试将NULL传递给集合的setter时。为了防止这种情况,我的setter看起来像这样:
public void setSubmittedForms(Set<SubmittedFormEntity> submittedForms) {
if(submittedForms == null) {
this.submittedForms.clear();
}
else {
this.submittedForms = submittedForms;
}
}