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 值
Hibernate如何正确删除@OneToMany中的孩子?
JPA 2 / Hibernate 孤儿删除仍然无法与@OneToMany 一起使用?
在 JPA/Hibernate 中使用 @OnetoMany 的实体中不存在时从数据库中删除子记录(Spring 引导应用程序)