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

时间:2016-02-23 16:51:09

标签: java hibernate orm parent-child cascade

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

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

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

删除父对象时,将按预期删除所有子对象,但会单独删除每个子对象。在我的应用程序中,父级可能有数千个子级,因此出于性能原因,我需要使用单个查询一次性删除它们。

可能的解决方法

  1. 在删除父级之前,手动执行我自己的HQL查询DELETE FROM child WHERE parent_id = ?。这里的缺点是我(和任何其他开发人员)必须记住调用该方法。此外,它基本上绕过了级联删除。
  2. 允许在数据库级别进行级联删除。由于数据在幕后变化,我假设我需要记住手动.clear()子集合以防止Hibernate与数据库之间的差异。
  3. 编辑:我看到旧版本的Hibernate曾经有one-shot delete的概念,但我在最新版本的文档中找不到任何相似内容。该功能是否已删除?

2 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:1)

这可能看起来过于简单,所以也许我不能正确理解你的问题,但是:

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

如果我们能够.clear()我们的孩子,就像那样。也许最好软删除它们,因为我们改变主意:)