Hibernate:使用一个查询删除所有 children

Hibernate: Delete all children with one query

TL;DR: 是否可以将 Hibernate 配置为使用单个删除查询删除所有 child objects?


完整问题: 我在 Hibernate 5.1 中定义了以下 parent/child 关联:

public class Parent {
  @OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", cascade = CascadeType.REMOVE)
  private List<Child> children;
}

public class Child {
  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = "parent_id", nullable = false)
  private Parent parent;
}

当我删除 parent object 时,所有 child object 都被删除,如预期的那样,但每个都被单独删除。在我的应用程序中,一个 parent 可能有数千个 children,因此出于性能原因,我需要使用单个查询一次将它们全部删除。

可能的解决方法

  1. 在删除 parent 之前手动执行我自己的 HQL 查询 DELETE FROM child WHERE parent_id = ?。这里的缺点是我(和任何其他开发人员)必须记住调用该方法。另外,它基本上绕过了级联删除。
  2. 允许级联删除发生在数据库级别。由于数据在幕后发生变化,我假设我需要记住手动 .clear() child 集合以防止 Hibernate 和数据库之间的差异。

编辑: 我看到旧版本的 Hibernate 曾经有 one-shot delete 的概念,但我在最新版本的文档中找不到任何类似的内容。该功能是否已删除?

  1. 假设您删除了父项。
  2. 如果其他 table,比如 GrandChild,有外键约束 对于 Child,每个 Child 都有多个 GrandChild 记录,他们 也需要删除。
  3. 生成多个删除查询的原因是,Hibernate 可以 不知道有没有其他的外键约束 tables,到"Child" table。也可能有一些回调方法需要执行,例如@PreRemove。这就是为什么每个子引用都从数据库中加载并单独删除的原因。
  4. 简而言之,如果您依赖 Hibernate 来管理您的实体,这 是默认行为。
  5. 要么在数据库中明确设置ON DELETE CASCADE,要么标记 带有注释的所需子实体 @org.hibernate.annotations.OnDelete,它会自动添加 "on delete" 在模式生成期间添加到模式。对于您的示例,它将是,

    `@OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", 
                cascade = CascadeType.REMOVE)    
     @org.hibernate.annotations.OnDelete(
                action = @org.hibernate.annotations.OnDeleteAction.CASCADE)
     private List<Child> children;
    

这似乎过于简单,所以我可能没有正确理解您的问题,但是:

Parent parent = parentRepository.findByName("dad");
parent.getChildren().clear();
entityManager.save(parent);

要是我们能.clear() 我们的children就好了。也许最好软删除它们以防我们改变主意:)