orphanRemoval在hibernate中无法正常工作:从列表中插入和删除的元素将保留在DB中

时间:2015-02-06 17:02:35

标签: java hibernate jpa orm hibernate-mapping

对于 oneToMany 列表 orphanRemoval = true >(带索引)。

这是简化的映射:

public class ParentClass {

  [...]

  @OneToMany(cascade = ALL, mappedBy = "parent", orphanRemoval = true)
  @OnDelete(action = OnDeleteAction.CASCADE)
  @Fetch(FetchMode.JOIN)
  @OrderColumn(name = "pos", nullable = false)
  public List<ChildClass> getChildren() {
    return children;
  }

}

孩子班:

public class ChildClass {
    [...]

    @ManyToOne
    @JoinColumn(nullable = false, name = "parent_id")
    public ParentClass getParent() {
        return parent;
    } 
}

鉴于此映射,以下方案失败:

  1. 从DB
  2. 中获取 Parent
  3. 添加一个孩子
  4. 从DB(不是同一实体)获取其他内容,生成部分刷新
  5. 从父母
  6. 中删除孩子
  7. 保留交易
  8. 这是代码

    @Transactional
    public void test() {
    
      // 1)
      ParentClass parent = entityManager.find(ParentClass.class, "some-id");
    
      // 2)
      ChildClass child = new ChildClass(parent);
      parent.getChildren().add(child);
    
      // 3)
      entityManager.find(SomethingElse.class, "2");
    
      // 4)
      parent.getChildren().remove(child);  
    }
    

    在这种情况下,子分配将插入到DB中,而不会在事务结束时删除。

    但是,如果我们不执行步骤3),则子分配正确无法在DB中保留

    这是一个错误吗?错误的映射? 它有解决方法吗?

3 个答案:

答案 0 :(得分:2)

是的,这是一个错误。我打赌你不会使用最新版本的Hibernate(4.3.8),并且它与这个问题有关(如果不是同一个问题):[HHH-9330] orphanRemoval=true does not work in bidirectional relationships (without cascading)即使你使用的是最后一个版本,这个bug仍然存在。如果是这样,请报告,然后在某处报告该错误的URL。解决方法:尝试仅在确定必须持久保存子项时添加子项,或者尝试将子项设置为使子项中的父项为空:

child.setParent(null);

另外,作为另一种解决方法,您可以尝试使用Hibernate会话,而不是使用EntityManager(因为它是在Hibernate&#39; s论坛中编写的)。

答案 1 :(得分:0)

删除子项时需要设置关联的两侧:

child.setParent(null);
parent.getChildren().remove(child);  

在您的情况下,孤儿清除是不够的。如果一对多方是单向关联,那么您可以简单地从列表中删除子项,删除将传播到子实体。

当你有双向关联时,你需要让双方同步。这就是为什么你需要在删除时将Child从Parent实体中解除关联。

答案 2 :(得分:0)

JPA注释@PreRemove可能对您的特定情况有所帮助。尝试将其添加到子实体,以便它可以从父项中删除它自己:

@PreRemove
protected void beforeRemove(){
    parent.getChildren().remove(this);
}