即使抛出错误,JPA EntityManager persist()也会导致对象显示为分离

Lin*_*k19 6 java hibernate jpa persist hibernate-entitymanager

嗨,我有一个简单的DAO具有以下功能.

    public element createElement(Element e){

    em.persist(e);
    em.flush();

    return e;
}
Run Code Online (Sandbox Code Playgroud)

Entity表对该对具有唯一约束(类型,值),我在下面进行了测试:

    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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我发现第一个被发现的错误就像我预期的那样,因为我知道我违反了约束,第二次尝试/ catch不应该抛出错误,但就确实如此,我得到了它:

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mypackage.Element
Run Code Online (Sandbox Code Playgroud)

所以它似乎在"e"上调用persist(),即使它没有持久化也导致hibernate认为它是一个独立的实体.

这很烦人,因为正在处理ConstraintViolation异常的JSF前端正在使用这些函数,但故意坚持使用该对象,以便用户可以更改其中一个字段并再次尝试,并且它们会获得分离的实体错误.

这种行为是一个hibernate错误,因为我认为它不应该这样做吗?在DAO级别有没有办法解决这个问题,以便坚持赢得;如果它实际上没有持久存在,我会把我的对象视为分离?

问候,

格伦x

JB *_*zet 3

Hibernate 抛出的异常是不可恢复的。发生此类异常时,您唯一应该做的就是回滚事务并关闭会话。发生此类异常后会话(及其实体)的状态是不稳定的。

如果您想保持元素的副本不受影响,请使用merge()而不是persist(),或在保留元素之前克隆该元素。

请注意,该异常是预期的,因为当 Hibernate 持久化并刷新实体时,它首先生成 ID 并将该 ID 分配给实体,然后插入行,这会导致异常。因此,在异常发生后,该实体会分配一个 ID,因此被 Hibernate 视为分离实体。您可以尝试将 ID 重置为 null 并查看它是否有效,但我更喜欢在合并之前克隆实体或使用合并。