【问题标题】:Hibernate update/delete one to many collectionHibernate 更新/删除一对多集合
【发布时间】:2021-10-22 08:22:46
【问题描述】:

我有两个类 ParentChild 具有一对多关系。

假设我已经在我的数据库结构中保持这样的状态:

Parent--> Child1, Child2

然后我得到了这个新结构(Child1 的变化,没有Child2 和新的Child3):

Parent--> Child1, ​Child3

所以:Child1 应该更新,Child2 应该被删除,Child3 应该被添加。

不幸的是,CasadeType.ALLorphanRemoval=true 的休眠只能添加和更新,但不会自动删除 Child2。我需要将列表与要更新的实体进行比较,并持久化一个以查找要删除的对象。

我想知道是否有任何模式可以优雅地解决我的问题,或者我是否应该更改 Hibernate 中的某些属性?

--- 编辑 ---

实体并不是什么花哨的东西,可以这样说:

@Entity
@Data
public class Parent {
   @Id
   @GeneratedValue(strategy = SEQUENCE)
   private long id;

   @OneToMany(mappedBy = "parent", casade = CasadeType.ALL, orphanRemoval = true)
   private Set<Child> childList;
}


@Entity
@Data
public class Child {
   @Id
   @GeneratedValue(strategy = SEQUENCE)
   private long id;

   @ManyToOne
   @JoinColumn(name = "xxx")
   private Parent parent;

}

【问题讨论】:

  • 您是否将 Child2 对 Parent 的引用设置为 null?
  • 我知道如何删除它。但我想知道是否有任何模式或内置方式来过滤此类对象。
  • 请显示您的实体类
  • @SimonMartinelli 没有什么花哨的。我刚刚更新了帖子。我只是想知道如何更改默认的 Hibernate 行为,或者是否有任何模式可以解决这个问题。
  • 当您从 Set 中移除 Child2 时,您设置 Parent parent = null?

标签: java hibernate jpa spring-data-jpa


【解决方案1】:

这是我遵循的模式:

    @Entity
    @Data
    public class Parent {
       @Id
       @GeneratedValue(strategy = SEQUENCE)
       private long id;

       @OneToMany(mappedBy = "parent", casade = CasadeType.ALL, orphanRemoval = true)
       private Set<Child> childList = new HashSet<>();
       
       public void addChild(Child child){

            if(child!=null){
              this.childList.add(child);
              child.setParent(this);   
            }
       }

       public void removeChild(Child child){

            if(child!=null){
              this.childList.remove(child);
              child.setParent(null);   
            }
       }

       public void updateChildren(Collection<Child> children){
           childList.forEach(x-> if(!children.contains(x)) this.removeChild(x); );
             
           children.forEach(x-> this.addChild(x));
       }
}

编辑

您可以像这样创建通用类并使用它。 注意:这很复杂

@MappedSuperClass
@Data
class Child<P extends Parent,C extends Child>{
        Parent<P,C> parent ;
}

@MappedSuperClass
@Data
class Parent<P extends Parent,C extends Child>{
    @Id
    @GeneratedValue(strategy = SEQUENCE)
    private long id;

    @OneToMany(mappedBy = "parent", casade = CasadeType.ALL, orphanRemoval = true)
    private Set<C> childList = new HashSet<>();

    public void addChild(C child){

        if(child!=null){
            this.childList.add(child);
            child.setParent(this);
        }
    }

    public void removeChild(C child){

        if(child!=null){
            this.childList.remove(child);
            child.setParent(null);
        }
    }

    public void updateChildren(Collection<C> children){
        childList.forEach(x-> {if(!children.contains(x)) this.removeChild(x); });

        children.forEach(this::addChild);
    }
}

【讨论】:

  • 这是一个安静的好答案。我想我们应该按其 id 过滤对象,而不是所有属性,因此除非我们实现 equals 函数来仅检查 id,否则它将不起作用。我也想知道更通用的方式。也许是一些像 Lombok 这样为我们生成代码的库或注释?
  • 对于任何对象比较,都知道 equals 和 hashCode 方法被覆盖 - 除非有人是 Java 新手。由于您需要更通用的方式,您可以创建自定义注释来执行此操作。
猜你喜欢
  • 2011-01-02
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 2014-01-05
  • 1970-01-01
  • 1970-01-01
  • 2013-07-12
  • 1970-01-01
相关资源
最近更新 更多