2012-02-24 62 views
6

您好我有以下功能的簡單的DAO()導致對象出現分離。JPA EntityManager的堅持,即使被拋出一個錯誤

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

如我所料,因爲我知道,我是我的第一個抓住了錯誤發生米違反約束,第二的try/catch應該不會引發錯誤就我而言,但它確實,我得到了這一點:

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mypackage.Element 

如此看來調用persist()的「電子「,即使它沒有持續下去導致hibernate認爲它是一個分離的實體。

這很煩人,因爲這些函數正在被處理ConstraintViolation異常的JSF前端使用,但是故意保留該對象,以便用戶可以更改其中一個字段並再次嘗試,並且它們會得到分離的實體錯誤。

這種行爲是休眠的錯誤,因爲我不認爲它應該被真正做這做?有沒有解決的辦法在DAO水平,使一直存在奪得;噸對待我的對象分開,如果它不是真正堅持?

問候,

格倫X

+0

只是爲了笑容,如果你創建一個新的元素和您呼叫的最後的createElement之前設置正確的價值觀發生了什麼? – 2012-02-24 16:43:16

+0

它很好。 – Link19 2012-02-24 16:43:56

+0

這有幫助嗎?如果沒有,這可能會工作... e.setValue(1); e = dao.createElement(e); (< - 將失敗),但然後e.setValue(2); edao.createElement(E); (< - 將有希望)。 – 2012-02-24 16:52:38

回答

3

由Hibernate拋出的異常是不可恢復的。在發生這種異常時,唯一應該做的事情是回滾事務並關閉會話。會議(及其實體)在這種例外之後的狀態是不穩定的。

如果你想保持元素的副本不變,使用merge()而非persist(),或者堅持之前克隆的元素。

注意,例外是意料之中的,因爲當休眠持續並刷新實體,它開始通過產生一個ID和分配ID的實體,然後插入一行,這會導致異常。所以,在例外之後,實體會分配一個ID,因此被Hibernate視爲一個分離的實體。你可以嘗試重置ID爲空,看看它是否有效,但我寧願先克隆實體或使用合併。