使用 JPA 注释自动从父项中删除子项和从子项中删除父项

Posted

技术标签:

【中文标题】使用 JPA 注释自动从父项中删除子项和从子项中删除父项【英文标题】:Delete child from parent and parent from child automatically with JPA annotations 【发布时间】:2014-07-18 11:39:10 【问题描述】:

假设我们有 3 个 Entities 对象类:

class Parent 
    String name;
    List<Child> children;


class Child 
    String name;
    Parent parent;


class Toy 
    String name;
    Child child;

如何使用 JPA2.x(或休眠)注解:

    父级删除时自动删除所有子级(一对多) 删除时自动从子列表中删除子(多对一) 孩子移除时自动删除玩具(一对一)

我正在使用 Hibernate 4.3.5 和 mysql 5.1.30。

谢谢

【问题讨论】:

【参考方案1】:

remove 实体状态转换应该从父级级联到子级,而不是相反。

你需要这样的东西:

class Parent 

    String name;

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    List<Child> children = new ArrayList<>();

    public void addChild(Child child) 
        child.setParent(this);
        children.add(child);
    

    public void removeChild(Child child) 
        children.remove(child);
        child.setParent(null);
    


class Child 

    String name;

    @ManyToOne
    Parent parent;
    
    @OneToOne(mappedBy = "child", cascade = CascadeType.ALL, orphanRemoval = true)
    Toy toy;


class Toy 
    String name;

    @OneToOne
    Child child;

【讨论】:

我有一个奇怪的问题。我们坚持或删除一些东西,它只是添加或删除,但下次我重新加载页面(再次查询)时,它就在那里,下次再次消失,它会随机继续!当我关闭 EntityManagerFactory(重新启动应用程序)时,一切都会好起来的! 我用添加/删除子方法更新了我的回复。确保始终同步父关联和子关联,因此当您添加新子时,父和子都知道新链接。确保您在 Transaction 中执行这些操作,您应该没问题。 EntityManagerFactory 应该仅在您的应用程序关闭时关闭。 List&lt;Toy&gt; toys 上映射Child 是错误的。应该是OneToMany。查看@JB Nizet in this post 的评论。更新你的答案。 是的,你说得对。它是 OneToOne 和只是 Toy 而不是 List&lt;Toy&gt; toys。所以,你在编辑答案之前就错了。现在完美了。 您不希望将删除操作从子级级联到父级是有道理的,但是在休眠中是否没有注释让子删除操作导致父集合中的子引用即将被删除?我想如果没有这样的注解就可以了,但是考虑到hibernate注解可以做的所有其他事情,这似乎并不合理。【参考方案2】:

您应该使用CascadeType.REMOVE。这是 Hibernate 和 JPA 的常见注释。 Hibernate 还有另一个类似的类型CacadeType,比如CascadeType.DELETE

    父级删除时自动删除所有子级(一对多)

    class Parent 
      String name;
    
      @OneToMany(cascade = CascadeType.REMOVE)
      List<Child> children;
    
    

    删除时自动从子列表中删除子(多对一)

    class Child 
     String name;
     @ManyToOne(cascade = CascadeType.REMOVE)
     Parent parent;
    
    

    子删除时自动删除玩具(一对一)

    class Toy 
      String name;
      @OneToOne(cascade = CascadeType.REMOVE)
      Child child;
    
    

【讨论】:

为什么要将删除从子级级联到父级,或从玩具级联到子级。这意味着当我移除一个玩具时,我移除了孩子,并且它是父母和他所有的孩子。【参考方案3】:

orphanRemoval 是删除所有孤儿实体示例:商店 (s) 有书 (b1,b2,b3) 并且 b1 有标题(t) 在这种情况下,如果删除了商店,一些书 (b2,b3) 将被删除. B2 和 t 仍然存在。如果您使用“cascade= CascadeType.Remove”,则只需存储所有书籍(仅存在“t”)。

s->b1,b2,b3 b2->t ------after(orphanRemoval = true)--------- b2->t

s->b1,b2,b3 b2->t ------ after(cascade=CascadeType.REMOVE)--------- t

如果指定了 orphanRemoval=true,则断开连接的实体实例将被自动删除。这对于清理在没有所有者对象引用的情况下不应该存在的依赖对象很有用。

如果仅指定cascade=CascadeType.REMOVE,则不会采取自动操作,因为断开关系不是删除操作。

【讨论】:

以上是关于使用 JPA 注释自动从父项中删除子项和从子项中删除父项的主要内容,如果未能解决你的问题,请参考以下文章

在JPA中删除子项时保持实体关系同步

JPA / Hibernate - 删除子项删除父项(从同一个表)

用于从 LastOrDefault 父项中查找子项的实体框架 LINQ

使用 Composition API 在 Vue 中处理子项和父项中的提交事件

如何反映从父项到子项的变化

查找并替换xml文档中父项中子项的重新匹配匹配项