JPA OneToMany不删除子项

问题

我在父实体和子实体之间使用simple@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;

  ...
}

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

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


#1 热门回答(225 赞)

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

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

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

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

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

我知道:

  • Hibernate:cascade delete_orphan。见10.11。传递性持久性;和
  • EclipseLink:称之为"私有制"。请参见如何使用@PrivateOwned注释。

#2 热门回答(65 赞)

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

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


#3 热门回答(34 赞)

你可以试试这个:

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