2017-08-17 50 views
1

我有一個簡單的編輯器UI用於在數據庫表上執行CRUD。 在休眠5.1下,過程如下:如何堅持一個分離的對象?

  1. 創建會話。讀入數據對象。關閉會話,分離對象。
  2. 使用分離的對象填充UI小部件。
  3. 允許用戶添加/編輯/刪除UI中的條目,修改分離的對象。
  4. 在用戶「保存」操作上:創建一個新的會話。使用saveOrUpdate()持久保存新的/更新的對象。關閉會議。
  5. 根據需要重複。

Hibernate 5.2強烈建議從Hibernate本地API移到JPA API。 JPA不允許您重新附加分離的對象。

有幾個解決方法:

  1. 使用展開來從JPA的EntityManager Hibernate的Session,並用它來調用saveOrUpdate。我不喜歡這個選項,因爲它依賴於不屬於JPA的功能。
  2. 使用JPA合併,它將更新持久對象,儘管我必須確保我不會破壞任何關聯。這給了我兩個同樣的對象,一個持續着,一個分開......這是混亂的。
  3. 執行手動合併操作,將分離對象中的修改字段複製到持久對象。這是額外的工作。
  4. 在整個過程中保持單個EntityManager實例處於活動狀態。不幸的是,其他線程可以在此會話仍處於打開狀態時執行CRUD操作,從而使持久性上下文與數據庫表不同步。所以我也不喜歡這種方法。

有沒有什麼好的方法可以做到這一點,或者這些是唯一的選擇?

回答

2

JPA不允許您重新附加分離的對象。

JPA規範定義了merge()操作。該操作似乎對實現所描述的用例很有用。

請參閱規格:

3.2.7.1合併獨立屋實體狀態

合併操作允許狀態,從分離的實體傳播到由實體管理器管理的持久性實體。是應用到實體X合併操作的語義如下:

  • 如果X是一個分離的實體,X的狀態被複制到預先存在的管理實體實例中的相同的標識或一個的X」 X的新託管副本X'被創建。
  • 如果X是新的實體實例,則會創建一個新的託管實體實例X',並將X的狀態複製到新的託管實體實例X'中。
  • 如果X是已刪除的實體實例,則合併操作將拋出IllegalArgumentException異常(否則事務提交將失敗)。
  • 如果X是一個託管實體,它將被合併操作忽略,但是,合併操作將級聯到由X關係引用的實體,如果這些關係已使用級聯元素值cascade = MERGE或cascade = ALL註解註解。
  • 對於所有由具有級聯元素值級聯= MERGE或級聯= ALL的X的關係引用的實體Y,Y以遞歸方式合併爲Y'。對於由X引用的所有這樣的Y,將X'設置爲引用Y'。 (注意,如果X被管理,則X與X'相同)
  • 如果X是合併到X'的實體,並引用另一個實體Y,其中級聯= MERGE或級聯= ALL未指定,然後從X相同的關聯導航「產生一個參照本發明的管理對象Y」具有相同的持久性身份Y.

持久化提供者不能合併標記的字段LAZY還沒有被取出:它必須合併時忽略這些字段。

實體使用的任何版本列必須由持久運行時實現在合併操作期間和/或在刷新或提交時檢查。在沒有Version列的情況下,在合併操作期間沒有由持久性提供者運行時執行額外的版本檢查。

- JSR 338: JavaTM Persistence API, Version 2.1, Final Release

+1

同意,合併是這裏最好的選擇。 +1 – StanislavL

1

我想你需要JPA合併樂觀鎖(實體中基於版本的字段)。如果實體發生了變化,您將無法將其保存回去。

因此分離它併合並回來(包括版本)。

還有業務邏輯問題,如果對象改變做什麼,用更新的值重試或發送一個錯誤給最終用戶,但最終的決定不是技術問題/