嗨,我有一个简单的DAO,具有以下功能。
public element createElement(Element e){
em.persist(e);
em.flush();
return e;
}
实体表对该对具有唯一约束(类型,值),我在下面进行了测试:
public void testCreateElement() throws DataAccessException {
// Start with empty Element table
Element e = new Element();
e.setType(myType.OTHER);
e.setValue("1");
dao.createElement(e);
e = new Element();
e.setType(MyType.OTHER);
e.setValue("1");
try{
// this should violate unique constraint of database.
dao.createElement(e);
} catch (Exception ex) {
System.out.println(ex);
}
e.setValue("2");
try{
// I expect this to work as there is no element with these values.
dao.createElement(e);
} catch (Exception ex) {
System.out.println(ex);
}
}
我的第一个被发现的错误正如我所料,因为我知道我违反了约束,第二次尝试/捕获不应该抛出错误,就我而言,但确实如此,我得到它的这个:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mypackage.Element
所以它似乎在“e”上调用persist(),即使它没有持久化也导致hibernate认为它是一个独立的实体。
这很烦人,因为正在处理ConstraintViolation异常的JSF前端正在使用这些函数,但故意保留对象以便用户可以更改其中一个字段并再试一次,然后他们得到了分离实体错误。
这种行为是一个hibernate错误,因为我认为它不应该这样做吗?在DAO级别有没有办法解决这个问题,以便坚持下去;如果实际上没有持续存在,我会将我的对象视为分离?
此致
Glen x
答案 0 :(得分:3)
Hibernate引发的异常无法恢复。发生此类异常时,您唯一应该做的就是回滚事务并关闭会话。此类异常后的会话状态(及其实体)不稳定。
如果您想保持元素的副本不变,请使用merge()
而不是persist()
,或者在保留元素之前克隆该元素。
请注意,异常是预期的,因为当Hibernate持续并刷新实体时,它首先生成一个ID并将ID分配给实体,然后插入导致异常的行。因此,在异常之后,实体具有分配的ID,因此被Hibernate视为分离的实体。您可以尝试将ID重置为null并查看它是否有效,但我更倾向于在使用合并之前克隆实体。