2011-11-09 17 views
1

也許我只是給你一小段代碼而過度簡化了這一點(如果是這種情況,我會發布更多的代碼),但我認爲,最初,更少更好:EntityManager嘗試插入實體而不被提示

我有一個資產類型的實體,它有一個位置類型的字段,它也是一個實體。當我設置資產的位置時,我還必須設置其子項的位置。

Location location = asset.getLocation(); 
em.merge(location); 
em.flush(); 

childAsset.setLocation(asset.getLocation()); 
em.flush(); 

當我運行的flush(),我得到以下異常:

內部異常:java.sql.SQLIntegrityConstraintViolationException:ORA-00001:唯一約束(SWRADMIN.LOCATION_PK)違反

我的問題是...爲什麼這個位置對象甚至試圖被持續?我所做的只是在一個實體中設置一個變量。

這工作很好,但我們只是切換到使用Eclipselink和Java EE 6,這個問題彈出。

解決方案?:我用「分離」的想法從下面並提出了以下變化:

Location location = asset.getLocation(); 

em.detach(childAsset); 
childAsset.setLocation(asset.getLocation()); 
em.merge(); 
em.flush(); 

和它的工作!我很困惑,爲什麼,但是......你會認爲自動同步會做同樣的事情。

回答

2

如果對象處於受管理狀態,則實體管理器將通過隱式持久對象(可能在事務結束時)或明確調用em.flush()方法時將其與底層數據庫同步。

您可以使用em.detach(entity)分離單個實體或em.clear()以分離所有實體。然後,對實體/實體所做的更改將不會反映在數據庫中。

爲了更好地處理此問題,您可以使用BMT(Bean Managed Transaction),您必須手動處理實體持久性事務。

編輯:

Location location = asset.getLocation(); 
childAsset.setLocation(location); 
em.merge(childAsset); 
em.flush(); 
+0

所以,我做了一個em.detach(childAsset),然後childAsset.setLocation(位置),然後em.merge(childAsset),它的工作!我的問題是...爲什麼?這不是同步開始時應該做的嗎? – wsaxton

+0

看着你原來的代碼,em.merge(location)然後em.flush()會在數據庫中持久化'location',然後在childAsset中設置它,然後再刷新'SQLIntegrityConstraintViolationException',因爲'location'已經存在於數據庫中。修改答案,參考編輯部分。 –

0

所以,位置是一個現有的位置,還是一個新的對象?

它是如何讀取的,是從另一個事務或實體管理器讀取還是以某種方式分離?如果是這樣,那麼你需要重新閱讀(查找)或合併它。

如果它是新的並且與託管對象相關,則是,flush必須寫入它。

+0

嗨,詹姆斯。我在帖子中添加了更多代碼。該位置是現有位置。爲了確保,我對位置對象執行了merge(),然後執行了flush()。它運行良好。當我將其分配給childAsset,然後執行另一個flush()時,我得到相同的錯誤。 – wsaxton

0

從代碼,它看起來像您正在使用位置的非託管版本,是相關聯的ChildAsset。如果您的childAsset-> Location關係標記爲cascade persist,則規範要求perist將在刷新或提交時在位置上調用。由於「位置」不是託管對象,因此它需要持久存在異常。

當位置被管理時(比如當你在ChildAsset上調用merge時,或者你已經使用了從 em.merge(location); call)返回的位置的託管實例時,ChildAsset-> Location上的持久操作是一個沒有操作。

不要將非託管實體關聯到標記級聯持久化的關係。

相關問題