【问题标题】:JPA OneToMany not deleting childJPA OneToMany 不删除孩子
【发布时间】: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 请求的一部分。按下保存按钮时,我没有已删除子项的列表,因此我无法隐式删除它们。

【问题讨论】:

    标签: java jpa jpa-1.0


    【解决方案1】:

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

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

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

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

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

    我知道:

    【讨论】:

    • 感谢很好的解释。就像我担心的那样。 (在我问之前我做了一些搜索/阅读,只是想保存)。不知何故,我开始后悔决定直接使用 JPA API 和 nit Hibernate .. 我会尝试 Chandra Patni 指针并使用 hibernate delete_orphan 级联类型。
    • 我有一个类似的问题。请在这里看看这篇文章好吗? stackoverflow.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 尚不支持此属性。

    【讨论】:

    【解决方案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。

          【讨论】:

            猜你喜欢
            • 2017-06-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-06-25
            • 2015-11-03
            • 1970-01-01
            相关资源
            最近更新 更多