JPA OneToMany不删除孩子

时间:2010-01-06 07:37:59

标签: 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>();

 ...
}

孩子:

@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请求的一部分发生的。按下保存按钮时,我没有已删除子项的列表,因此我无法隐式删除它们。

7 个答案:

答案 0 :(得分:239)

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

部分原因是因为JPA实际上并不知道是否应删除从集合中删除的内容。在对象建模术语中,这是组合和“聚合*。

之间的区别

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

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

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

我知道:

答案 1 :(得分:69)

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

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

答案 2 :(得分:41)

你可以试试这个:

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

答案 3 :(得分:18)

正如所解释的那样,不可能用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',因为这也会删除父亲。

答案 4 :(得分:3)

此处,在“删除”的上下文中,级联意味着如果删除父级,则会删除子级。不是协会。如果您使用Hibernate作为JPA提供程序,则可以使用hibernate specific cascade

执行此操作

答案 5 :(得分:2)

@Entity 
class Employee {
     @OneToOne(orphanRemoval=true)
     private Address address;
}

请参阅here

答案 6 :(得分:1)

你可以试试这个:

$('.check').click( function () {
    var score = 0
    var all = $('input[id^=" "]');
    var checked = $('input:checked');
    var good = $('input:checked[id^=" "]');

    checked.siblings().css('color', 'red');
    all.siblings().css('color', 'green');
    good.each ( function(){
        score += 1;
    })

    alert(score);
    score = 0;
});

@OneToOne(cascade = CascadeType.REFRESH)