首页 > 解决方案 > JPA 不安排删除孤儿和多态集合

问题描述

请看代码。

    for (CowRow row : entity.getCowRows()) {
        em.remove(row.getCowRowData());
        em.remove(row);
    }
    entity.getCowRows().clear();

在哪里

@Entity
@Table(name = "cowrow")
public class CowRow {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private Cow cow;

    private int rowNumber;

    @OneToOne(mappedBy = "cowRow", cascade = CascadeType.ALL, orphanRemoval = true)
    private CowRowData cowRowData;
//accessors here
}

CowRowData 是 CowPriceTag 和 CowReasoning 的父实体。“实体”是包含以下内容的 Cow:

@OneToMany(mappedBy = "cow", orphanRemoval = true)
private Collection<CowRow> cowRows;

在刷新时,此代码片段会生成一个日志:

2018-05-07 11:20:21.351 TRACE 15892 --- [nio-8080-exec-1] org.hibernate.engine.internal.Cascade    : Processing cascade ACTION_PERSIST_ON_FLUSH for: ru.dz.bis.entities.Cow
2018-05-07 11:20:21.353 TRACE 15892 --- [nio-8080-exec-1] org.hibernate.engine.internal.Cascade    : Done processing cascade ACTION_PERSIST_ON_FLUSH for: ru.dz.bis.entities.Cow

还有一些关于级联的记录,没有关于 CowRow 或 CowRow 的记录。

但是,如果我删除那个“for”循环——人们会期望清除一个集合会导致删除孤立的 CowRow 实例。但是,由于某种原因,删除会被取消计划,并带有以下奇怪的日志:

2018-05-07 11:40:49.342 TRACE 19739 --- [nio-8080-exec-3] org.hibernate.engine.internal.Cascade    : Processing cascade ACTION_PERSIST_ON_FLUSH for: ru.dz.bis.entities.Cow
2018-05-07 11:40:49.343 TRACE 19739 --- [nio-8080-exec-3] org.hibernate.engine.internal.Cascade    : Done processing cascade ACTION_PERSIST_ON_FLUSH for: ru.dz.bis.entities.Cow
2018-05-07 11:40:49.343 TRACE 19739 --- [nio-8080-exec-3] org.hibernate.engine.internal.Cascade    : Processing cascade ACTION_PERSIST_ON_FLUSH for: ru.dz.bis.entities.Folder
2018-05-07 11:40:49.344 TRACE 19739 --- [nio-8080-exec-3] org.hibernate.engine.internal.Cascade    : Done processing cascade ACTION_PERSIST_ON_FLUSH for: ru.dz.bis.entities.Folder
2018-05-07 11:40:49.345 TRACE 19739 --- [nio-8080-exec-3] org.hibernate.engine.internal.Cascade    : Processing cascade ACTION_PERSIST_ON_FLUSH for: ru.dz.bis.entities.CowRow
2018-05-07 11:40:49.346 TRACE 19739 --- [nio-8080-exec-3] o.hibernate.engine.spi.CascadingAction   : Cascading to persist on flush: ru.dz.bis.entities.CowRowData
2018-05-07 11:40:49.346 TRACE 19739 --- [nio-8080-exec-3] o.h.e.i.AbstractSaveEventListener        : Persistent instance of: ru.dz.bis.entities.CowRowData
2018-05-07 11:40:49.347 TRACE 19739 --- [nio-8080-exec-3] o.h.e.i.DefaultPersistEventListener      : Ignoring persistent instance
20

如果 orphanRemoval 工作正常,为什么 JPA 坚持 CowRow?我清除了 Cow.cowRows,JPA 应该安排这些行进行删除。并且日志中没有提到取消计划!

好吧,让我们试试别的。让我们在“for”循环中执行“em.remove(row.getCowRowData())”。现在我看到了:

2018-05-07 11:54:26.869 TRACE 22914 --- [nio-8080-exec-1] org.hibernate.engine.internal.Cascade    : Processing cascade ACTION_PERSIST_ON_FLUSH for: ru.dz.bis.entities.CowRow
2018-05-07 11:54:26.870 TRACE 22914 --- [nio-8080-exec-1] o.hibernate.engine.spi.CascadingAction   : Cascading to persist on flush: ru.dz.bis.entities.CowRowData
2018-05-07 11:54:26.873 TRACE 22914 --- [nio-8080-exec-1] o.h.e.i.AbstractSaveEventListener        : Deleted instance of: ru.dz.bis.entities.CowRowData
2018-05-07 11:54:26.878 TRACE 22914 --- [nio-8080-exec-1] o.h.e.i.DefaultPersistEventListener      : un-scheduling entity deletion [[ru.dz.bis.entities.CowPriceTag#8]]

所以 1)依赖 orphanRemoval 和进行手动删除之间存在区别,2)JPA 出于某种原因处理 RowData 的级联持久化,3)在处理这个持久级联时,JPA 说它删除了一个 CowRowData(为什么是现在?可能是因为orphanRemoval?), 4) 并在此之后立即取消删除,就像因为这个 CowRowData 引用了 CowPriceTag (好的,但它是同一个实体 - 它的子类!最重要的是,它被删除了!)

只有当我也在循环中执行“em.remove(row)”时,代码才能按设计工作。尽管现在还不完全是:删除 row.getCowRowData() 应该使 CowRowData 成为孤儿(在 CowRow->CowRowData 中)并安排将其删除(类似于本例中的 CascadeType.REMOVE),但这不会发生。

这一切意味着什么?

也许 orphanRemoval 不适用于多态集合?还是我?

标签: hibernatejpa

解决方案


推荐阅读