我有以下问题时,试图更新我的实体:
"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;
检查所有你给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);
}
我最近在重构一些代码时遇到了这个问题。原始的(正确的)代码是这样的:
public virtual IEnumerable<SubscriptionPurchase> Purchases => _purchases;
public virtual SubscriptionPurchase MostRecentPurchase => _purchases.OrderByDescending(p => p.PurchaseDateUtc).FirstOrDefault();
我尝试通过将. orderbydescent移动到. purchasing属性来更改代码。这个更改破坏了代码,并导致OP中的引用错误:
public virtual IEnumerable<SubscriptionPurchase> Purchases => _purchases.OrderByDescending(p => p.PurchaseDateUtc);
public virtual SubscriptionPurchase MostRecentPurchase => Purchases.FirstOrDefault();
直到试图保存包含. purchasing属性的父对象时,错误才显示出来。
正如对这个问题的其他回答所指出的那样,出现这个问题是因为集合正在重置(在我的例子中是在对. purchasing的每个访问上)。
我使用Spring Boot,有这个问题与一个集合,尽管没有直接覆盖它,因为我声明了一个额外的字段为同一个集合与自定义序列化和反序列化,以提供一个更前端友好的数据表示:
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);
}