【问题标题】:Delete child from parent and parent from child automatically with JPA annotations使用 JPA 注释自动从父项中删除子项和从子项中删除父项
【发布时间】: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(或休眠)注解:

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

我正在使用 Hibernate 4.3.5 和 mysql 5.1.30。

谢谢

【问题讨论】:

    标签: java hibernate jpa orm hibernate-mapping


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

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

      class Parent {
        String name;
      
        @OneToMany(cascade = CascadeType.REMOVE)
        List<Child> children;
      }
      
    2. 删除时自动从子列表中删除子(多对一)

      class Child {
       String name;
       @ManyToOne(cascade = CascadeType.REMOVE)
       Parent parent;
      }
      
    3. 子删除时自动删除玩具(一对一)

      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,则不会采取自动操作,因为断开关系不是删除操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      • 2016-08-03
      • 1970-01-01
      • 2011-04-13
      • 2017-10-02
      • 1970-01-01
      相关资源
      最近更新 更多