JPA OneToMany不删除孩子

ber*_*ert 148 java jpa jpa-1.0

@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>();

 ...
}
Run Code Online (Sandbox Code Playgroud)

孩子:

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

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

  ...
}
Run Code Online (Sandbox Code Playgroud)

如果我现在从子集Set中删除和子节点,它不会从数据库中删除.我试图使child.parent引用无效,但这也无效.

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

cle*_*tus 245

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

在某种程度上,这是因为JPA实际上并不知道它是否应该删除从集合中删除的内容.在对象建模术语中,这是组合与"聚合*" 之间的差异.

组合中,没有父项,子实体就不存在.House和Room之间有一个典型的例子.删除房子和房间也去.

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

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

我知道:

  • 使用JPA 2.0,您现在可以使用选项orphanRemoval = true (74认同)
  • 关于orphanRemoval的很好的初步解释和好建议.不知道JPA没有解释这种类型的删除.我所知道的关于Hibernate和JPA实际上所做的事情之间的细微差别令人抓狂. (2认同)

Lou*_*met 69

除了cletus的回答,JPA 2.0,2010年12月以来的最终版本,引入了注释orphanRemoval属性@OneToMany.有关详细信息,请参阅此博客条目.

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

  • 回程机的魔力拯救了我们:https://web.archive.org/web/20120225040254/http://javablog.co.uk/2009/12/27/onetomany-fixes-in-jpa-2/ (3认同)

Mac*_*ato 41

你可以试试这个:

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

  • 不过要知道,对于我们这些在JPA2中寻找解决方案的人来说:) (8认同)
  • 谢谢.但问题是从JPA回来了1次.并且这个选项不可用. (2认同)

ber*_*ert 19

正如所解释的那样,不可能用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>();
Run Code Online (Sandbox Code Playgroud)

我不能简单地使用'ALL',因为这也会删除父母.


Cha*_*ang 7

@Entity 
class Employee {
     @OneToOne(orphanRemoval=true)
     private Address address;
}
Run Code Online (Sandbox Code Playgroud)

这里