Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 孤立删除在hibernate中无法正常工作:从列表中插入和删除的元素在数据库中保持不变_Java_Hibernate_Jpa_Orm_Hibernate Mapping - Fatal编程技术网

Java 孤立删除在hibernate中无法正常工作:从列表中插入和删除的元素在数据库中保持不变

Java 孤立删除在hibernate中无法正常工作:从列表中插入和删除的元素在数据库中保持不变,java,hibernate,jpa,orm,hibernate-mapping,Java,Hibernate,Jpa,Orm,Hibernate Mapping,我们有一个问题,听起来像是Hibernate中的一个bug在处理孤儿删除问题=对于oneToMany列表(带索引) 以下是简化的映射: public class ParentClass { [...] @OneToMany(cascade = ALL, mappedBy = "parent", orphanRemoval = true) @OnDelete(action = OnDeleteAction.CASCADE) @Fetch(FetchMode.JOIN) @O

我们有一个问题,听起来像是Hibernate中的一个bug在处理孤儿删除问题=对于oneToMany列表(带索引)

以下是简化的映射:

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;
  }

}
鉴于此映射,以下场景将失败:

  • 从数据库中获取父级
  • 给它添加一个子元素
  • 从DB(不是同一个实体)获取其他内容,生成部分刷新
  • 从父对象中删除子对象
  • 退出交易
  • 这是密码

    @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),则子分配不会正确地持久化到数据库中

    那是虫子吗?错误的映射?
    有解决方法吗?

    是的,这是一个bug。我打赌你没有使用Hibernate的最新版本(4.3.8),而且它与这个问题相关(如果不是同一个问题):即使你使用最新版本,这个bug仍然可能存在。如果是这样,请报告它,然后在这里的某个地方向bug报告URL。解决方法:仅当确定必须持久化子项时,才尝试添加该子项,或者尝试将子项中的父项设置为null:

    child.setParent(空)


    另外,作为另一种解决方法,您可以尝试使用Hibernate会话,而不是EntityManager(正如在Hibernate论坛中所写的那样)。

    删除孩子时,您需要设置关联的双方:

    child.setParent(null);
    parent.getChildren().remove(child);  
    
    在你的情况下,孤儿的移除是不够的。如果一对多端是单向关联,那么您只需从列表中删除子对象,删除操作就会传播到子实体


    当您具有双向关联时,您需要使双方同步。这就是为什么在删除时需要将子实体与父实体解除关联。

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

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

    恐怕双向关系中的orpahnRemoval功能也应该起作用。我在回答中发布的链接是讨论内容的地方。谢谢,我只是尝试了一下,在4)处将parent设置为null,而不是DELETE,in生成一个更新,parentId为null,这是DB禁止的(我们有显式的notnull约束)。顺便说一句,我们使用Hibernate 4.2.2,我明白了,为什么不调用
    em.remove(child)相反(当然是workadound)?是的,这就是我们最终要做的。只是目前我们依赖于这样一种断言,即Hibernate可以很好地遍历模型的状态,而无需每次删除某些内容时都显式地调用em.remove()。这也带来了一些设计上的不一致性:我们不希望在低级业务服务中使用任何与持久性相关的服务。我担心,只要您不更新到最新版本(请注意,版本4.3.7似乎也会受到影响,因为此错误更正是最近的),您就必须执行这些操作(您至少应该在代码中添加一条注释,并带有bug链接)。我的意思是,你最好保持这段代码的原样,不要有引入新错误/不希望出现的行为的风险,因为它至少现在起作用。如果你想继续抱怨JPA,那么你不允许访问/更改任何关系。你只允许更改自己的属性,如字符串、原语……但不允许更改任何关系。
    
    @PreRemove
    protected void beforeRemove(){
        parent.getChildren().remove(this);
    }