JPA OneToMany 不删除孩子

Posted

技术标签:

【中文标题】JPA OneToMany 不删除孩子【英文标题】:JPA OneToMany not deleting child 【发布时间】:2011-01-01 23:05:55 【问题描述】:

我对父实体和子实体之间的简单@OneToMany 映射有疑问。一切都很好,只有当我从集合中删除子记录时不会删除它们。

父母:

@Entity
public class Parent 
    @Id
    @Column(name = "ID")
    private Long id;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
    private Set<Child> childs = new HashSet<Child>();

 ...

孩子:

@Entity
public class Child 
    @Id
    @Column(name = "ID")
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="PARENTID", nullable = false)
    private Parent parent;

  ...

如果我现在从子集中删除和子集,它不会从数据库中删除。我尝试取消 child.parent 引用,但这也不起作用。

实体在 Web 应用程序中使用,删除是 Ajax 请求的一部分。按下保存按钮时,我没有已删除子项的列表,因此我无法隐式删除它们。

【问题讨论】:

【参考方案1】:

JPA 的行为是正确的(意味着按照规范):对象不会因为您从 OneToMany 集合中删除而被删除。有一些特定于供应商的扩展可以做到这一点,但原生 JPA 不能满足它。

这部分是因为 JPA 实际上并不知道它是否应该删除从集合中删除的内容。在对象建模方面,这就是 composition 和“aggregation*”之间的区别。

composition中,子实体没有父实体就没有存在。一个典型的例子是 House 和 Room 之间。删除房子,房间也会消失。

聚合 是一种较松散的关联,以 Course 和 Student 为代表。删除课程,学生仍然存在(可能在其他课程中)。

因此,您需要使用特定于供应商的扩展来强制执行此行为(如果可用)或显式删除子项并将其从父项的集合中删除。

我知道:

Hibernate:级联删除孤儿。见10.11. Transitive persistence;和 EclipseLink:称之为“私有制”。见How to Use the @PrivateOwned Annotation。

【讨论】:

感谢很好的解释。就像我担心的那样。 (在我问之前我做了一些搜索/阅读,只是想保存)。不知何故,我开始后悔决定直接使用 JPA API 和 nit Hibernate .. 我会尝试 Chandra Patni 指针并使用 hibernate delete_orphan 级联类型。 我有一个类似的问题。请在这里看看这篇文章好吗? ***.com/questions/4569857/… 使用 JPA 2.0,您现在可以使用选项 orphanRemoval = true 关于 orphanRemoval 的很好的初步解释和很好的建议。不知道 JPA 没有考虑这种类型的删除。我对 Hibernate 的了解与 JPA 实际所做的事情之间的细微差别可能令人抓狂。 通过揭示组合和聚合之间的差异很好地解释了!【参考方案2】:

除了 cletus 的回答之外,JPA 2.0,自 2010 年 12 月以来的最终版本,在 @OneToMany 注释上引入了 orphanRemoval 属性。 有关更多详细信息,请参阅blog entry。

请注意,由于规范相对较新,并非所有 JPA 1 提供者都有最终的 JPA 2 实现。例如,Hibernate 3.5.0-Beta-2 release 尚不支持此属性。

【讨论】:

博客条目 - 链接已损坏。 而返航机的魔力拯救了我们:web.archive.org/web/20120225040254/http://javablog.co.uk/2009/…【参考方案3】:

你可以试试这个:

@OneToOne(orphanRemoval=true) or @OneToMany(orphanRemoval=true).

【讨论】:

谢谢。但是问题是从 JPA 1 回来的。并且该选项不可用。 很高兴知道,对于我们这些在 JPA2 时代寻找解决方案的人来说 :)【参考方案4】:

正如解释的那样,用 JPA 做我想做的事情是不可能的,所以我使用了 hibernate.cascade 注释,这样,Parent 类中的相关代码现在看起来像这样:

@OneToMany(cascade = CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, mappedBy = "parent")
@Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE,
            org.hibernate.annotations.CascadeType.DELETE,
            org.hibernate.annotations.CascadeType.MERGE,
            org.hibernate.annotations.CascadeType.PERSIST,
            org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Child> childs = new HashSet<Child>();

我不能简单地使用“ALL”,因为这也会删除父级。

【讨论】:

【参考方案5】:

这里的级联,在remove的上下文中,意味着如果你删除了父级,子级也会被删除。不是协会。如果您使用 Hibernate 作为您的 JPA 提供程序,则可以使用 hibernate specific cascade。

【讨论】:

【参考方案6】:

你可以试试这个:

@OneToOne(cascade = CascadeType.REFRESH) 

@OneToMany(cascade = CascadeType.REFRESH)

【讨论】:

【参考方案7】:
@Entity 
class Employee 
     @OneToOne(orphanRemoval=true)
     private Address address;

见here。

【讨论】:

以上是关于JPA OneToMany 不删除孩子的主要内容,如果未能解决你的问题,请参考以下文章

在 JHipster 的 @OneToMany JPA 关系中编写孩子的问题

如何在 Spring Boot JPA 中的 OneToMany 中为孩子获取 Null 值

Spring JPA OneToMany 集合不删除条目

Hibernate如何正确删除@OneToMany中的孩子?

JPA 2 / Hibernate 孤儿删除仍然无法与@OneToMany 一起使用?

在 JPA/Hibernate 中使用 @OnetoMany 的实体中不存在时从数据库中删除子记录(Spring 引导应用程序)