我正在尝试从双向关联中删除子元素。我的说法是,如果我查询Employee实例,然后使用getChildren()
方法来获取关联的子代,则父代和子代记录都将得到管理。现在,当我调用child.setParent(null)
和parent.getChildren().remove(child)
时,事务提交时两个更新都应该保留,但是我得到了:org.hibernate.AssertionFailure: collection [org.rand.model.Employee.children] was not processed by flush()
异常,除非我在子元素上调用merge或通过查询获取子元素。
有人可以解释为什么会这样吗?
我正在使用休眠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();
}
}
[可能是因为在removeChildWithMerge中,您的子级集合是延迟加载的,并且在刷新期间触发了导致此异常的项目的加载。您可以使用Hibernate.inititalize(obj)而不是调用merge。另一方面,在removeChildWithFetch中,您正在使用fetch来急切地加载集合并因此加载集合项。因此在刷新期间,项目已加载,因此没有问题。
对于我来说,我是通过以下方式解决的:
@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;