【问题标题】:collection was not processed by flush()集合没有被 flush() 处理
【发布时间】:2014-07-15 09:53:24
【问题描述】:

我正在尝试从双向关联中删除子元素。我的理解是,如果我查询 Employee 实例,然后使用 getChildren() 方法获取关联的子项,则父子记录都被管理。现在,当我调用 child.setParent(null)parent.getChildren().remove(child) 时,事务提交时这两个更新都应该保持不变,但是我得到:org.hibernate.AssertionFailure: collection [org.rand.model.Employee.children] was not processed by flush() 异常,除非我在子元素上调用合并或通过查询获取子元素。

有人可以解释为什么会这样吗?

我使用的是休眠 3.5.6-Final

谢谢

更新:经过一段时间的调试后,我发现了导致此错误的代码,我一定是在发布问题时不小心删除了它。我对此深表歉意。

罪魁祸首是自定义 OneToManyInverseCheck bean 验证器,它正在验证是否在父子节点上都设置了关系。这会在提交操作期间触发加载其他实体(子项的子项)。

实体:

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy=GenerationType.TABLE)
    private int id;

    @Version
    private int version;

    private String name;

    @ManyToOne
    private Employee parent;

    @OneToMany(mappedBy="parent")
    @OneToManyInverseCheck(inverseFieldName="parent")
    private List<Employee> children; 

    //get/set methods ommitted 
}

简单的 JUnit:

public class JPAUpdate {

    private static EntityManagerFactory emf;
    private EntityManager em;

    @BeforeClass
    public static void init() {
        emf = Persistence.createEntityManagerFactory("myapp-db");
    }

    @Before
    public void setUp() throws Exception {
        em = emf.createEntityManager();
    }

    @Test
    public void removeChildWithMerge() {
       em.getTransaction().begin();
       Employee e = em.createQuery("from Employee e where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0);

        Employee child = e.getChildren().get(0);

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

        // removing this merge causes org.hibernate.AssertionFailure: collection [org.rand.model.Employee.children] was not processed by flush()
        em.merge(child);
        em.getTransaction().commit();
    }

    @Test
    public void removeChildWithFetch() {
        em.getTransaction().begin();
        Employee e = em.createQuery("from Employee e left join fetch e.children where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0);

        Employee child = e.getChildren().get(0);
        child.setParent(null);
        e.getChildren().remove(child);
        //em.merge(child); - no merge needed
        em.getTransaction().commit();
    }

    @Test
    public void removeChild() {
        em.getTransaction().begin();
        Employee e = em.createQuery("from Employee e left join fetch e.children where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0);

        Employee child = e.getChildren().get(0);
        child.setParent(null);
        e.getChildren().remove(child);
        //em.merge(child); - no merge needed
        em.getTransaction().commit();
    }
}

【问题讨论】:

  • 它应该被管理,所以检查“em.contains()”。如果它是托管的,那么您永远不需要按 JPA 规范调用合并。如果它不是托管的,那么您必须问一个问题,为什么 Hibernate 分发非托管对象...

标签: hibernate jpa jpa-2.0 bean-validation


【解决方案1】:

这可能是因为在 removeChildWithMerge 中您的子集合被延迟加载,并且在刷新期间触发了导致此异常的项目的加载。您可以使用 Hibernate.inititalize(obj) 而不是调用合并。另一方面,在 removeChildWithFetch 中,您使用 fetch 急切地加载集合并因此加载集合项目。因此,在刷新期间,项目已经加载,所以没有问题。

【讨论】:

  • 当其他 JPA 实现(和 JPA 规范)不需要时,为什么你必须调用一些特定于实现的函数?
  • 我完全同意 Neil。但这只是另一种选择。无论如何感谢您的指出。
【解决方案2】:

对于我的情况,我通过以下方式解决了它:

@PersistenceContext(type = PersistenceContextType.EXTENDED)
  private EntityManager entityManager;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-12
    • 1970-01-01
    • 2011-05-01
    • 2021-02-13
    • 1970-01-01
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多