我有以下问题时,试图更新我的实体:

"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<..只有>,根据这个:如何“可能”解决问题,但它没有工作。

如果你有什么想法,请告诉我。

谢谢!


当前回答

当我设置parent时,拥有的实体实例不再引用级联= " all-delete-orphan "的集合。setChildren(新ArrayList < >())。当我改为parent.getChildren().clear()时,它解决了这个问题。

请查看更多详细信息:HibernateException - cascade="all-delete-orphan"的集合不再被所属实体实例引用。

其他回答

在我的例子中,它是从几个线程并发访问一个Hibernate会话。 我有Spring Boot Batch和RepositoryItemReader实现,其中我通过大小为10的页面请求获取实体。

例如,我的实体是:

@Entity
class JobEntity {
    @ManyToOne(fetch = FetchType.LAZY)
    private GroupEntity group;
}

@Entity
class GroupEntity {
    @OneToMany(mappedBy = "group", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private Set<Config> configs; 
}

批处理:在一个事务中读取器->处理器->写入器。

在该实体配置中,GroupEntity可以转义到其他线程:

进入read部分的第一个线程获取大小为10的JobEntity页面(RepositoryItemReader#doRead),该项目包含一个共享的GroupEntity对象(因为它们都指向相同的组id)。然后取第一个实体。接下来读取部分的线程一个接一个地从该页中取出JobEntity,直到耗尽该页。

所以现在线程可以访问与JobEntity实例相同的GroupEntity实例,这是不安全的多线程访问一个Hibernate会话。

从[Intellij Idea] 2020.3版本批量运行测试时,spring-boot 2.4.1出现此问题。从IntelliJ一次只运行一个测试或从命令行运行测试时,不会出现此问题。

也许是Intellij缓存问题?

跟进:

The problem appears when running tests using the maven-surefire-plugin reuseForks true. Using reuseForks false would provide a quick fix, but the tests running time will increase dramatically. Because we are reusing forks, the database context might become dirty due to other tests that are run - without cleaning the database context afterwards. The obvious solution would be to clean the database context before running a test, but the best one should be to clean up the database context after each test (solving the root cause of the original problem). Using the @Transactional annotation on your test methods will guarantee that your database changes are rolled back at the end of the test methods. See the Spring documentation on transactions: https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#testcontext-tx.

这与之前的答案相反,我有完全相同的错误:“级联=“all-delete-orphan”的集合不再引用....”,当我的setter函数看起来像这样:

public void setTaxCalculationRules(Set<TaxCalculationRule> taxCalculationRules_) {
    if( this.taxCalculationRules == null ) {
        this.taxCalculationRules = taxCalculationRules_;
    } else {
        this.taxCalculationRules.retainAll(taxCalculationRules_);
        this.taxCalculationRules.addAll(taxCalculationRules_);
    }
}

然后当我把它改成简单的版本时,它就消失了:

public void setTaxCalculationRules(Set<TaxCalculationRule> taxCalculationRules_) {
    this.taxCalculationRules = taxCalculationRules_;
}

(hibernate版本-尝试了5.4.10和4.3.11。在回到setter中的简单赋值之前,花了几天时间尝试各种解决方案。现在很困惑为什么会这样。)

方法:

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

@OneToMany(mappedBy = "entity_b", cascade = [CascadeType.]所有],orphanRemoval = true)

我也遇到了同样的错误。当我删除上面结构中的;"orphanRemoval = true"部分时,它工作了