JPA:DELETE WHERE不会删除子项并抛出异常

Jea*_*art 26 java hibernate jpa jpql

MOTHER感谢JPQL查询,我试图删除大量的行.

所述Mother类的定义如下:

@Entity
@Table(name = "MOTHER")
public class Mother implements Serializable {

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "mother", 
               orphanRemoval = true)
    private List<Child> children;    
}

@Entity
@Table(name = "CHILD")
public class Child  implements Serializable {

    @ManyToOne
    @JoinColumn(name = "MOTHER_ID")
    private Mother mother;    
}
Run Code Online (Sandbox Code Playgroud)

如您所见,Mother该类具有"子",并在执行以下查询时:

String deleteQuery = "DELETE FROM MOTHER WHERE some_condition";
entityManager.createQuery(deleteQuery).executeUpdate();
Run Code Online (Sandbox Code Playgroud)

抛出异常:

ERROR - ORA-02292: integrity constraint <constraint name> violated - 
                   child record found
Run Code Online (Sandbox Code Playgroud)

当然,我可以首先选择我要删除的所有对象,然后在迭代它之前将它们检索到列表中以删除所有检索到的对象,但是这样的解决方案的性能会很糟糕!

那么有没有办法利用前面的映射来有效地删除所有Mother对象和Child与它们相关的所有对象,而无需首先为所有子项编写查询?

Mik*_*unu 35

DELETE(和INSERT)不会通过JPQL查询中的关系级联.这清楚地说明了规范:

删除操作仅适用于指定类及其子类的实体.它不会级联到相关实体.

幸运地坚持并通过实体管理器删除(当定义了级联属性时).

你可以做什么:

  • 获取应删除的所有Mother实体实例.
  • 对于他们每个人调用EntityManager.remove().

代码是这样的:

String selectQuery = "SELECT m FROM Mother m WHERE some_condition";  
List<Mother> mothersToRemove = entityManager
    .createQuery(selectQuery)
    .getResultStream()
    .forEach(em::remove);
Run Code Online (Sandbox Code Playgroud)

  • 遗憾的是,这会破坏批量删除带来的性能优势,并且除了玩具情况之外,您还需要将selectQuery包装到一个分页基础结构中,这样可以清除每页的entermanager以避免大量Mothers的内存耗尽. (9认同)
  • 实际上,通常EntityManager.remove()尚未调用数据库,这在稍后的刷新/提交时间内会发生. (6认同)
  • 每次我在循环中看到数据库调用时,我都会畏缩.这是SOOOOO缓慢,资源密集,效率低下!总有更好的方法!:) (4认同)