2012-10-05 60 views
1

試想一下簡單的「樹」 JPA實體:瞭解EntityManager的合併操作的行爲

public class TreeItem { 
    @OneToMany(mappedBy = "parentItem") 
    private List<TreeItem> childItems; 
    @ManyToOne 
    @JoinColumn(name = "parent_id" 
    private TreeItem parentItem; 
    @Column 
    private String name; 
} 

現在這些實體被加載一個,傳遞到網絡層,更新並傳回給EJB的保存操作。我注意到,在執行merge()操作期間,無論樹實體駐留多深,在發出一個update sql命令之前,整個樹都會被加載。這是爲什麼發生?我無法看到這種行爲背後的原因,因爲我沒有設置級聯選項。

更新: 是的,傳回的實體是分離的,需要將其狀態與數據庫層同步,這就是我的理解。但是我不明白的是,爲什麼同步需要閱讀整棵樹,而不考慮懶惰的關係。

+0

你的問題不清楚。顯示代碼。一般而言,如果傳遞給合併的實體被分離,那麼它的狀態將從數據庫加載,以創建新的託管圖。如果你不明白爲什麼會發生這種情況,我的猜測是你並不真正理解merge()的語義。在傳遞給merge()的分離對象的情況下,合併將返回一個新實例化對象(圖)作爲分離狀態的託管表示。這就是merge()有回報的原因。至於它加載多少,那麼取決於我說你的問題還不夠清楚。 –

+0

@Steve,謝謝,我會更新這個問題,是的 - 實體是分離的,但我仍然不明白爲什麼'合併'應該加載整個樹來做更多的查詢而不是'em.find()' – Osw

+0

你會意識到該parentItem是不是懶惰的權利? –

回答

0

這裏的說明書中如何定義合併操作:

應用到實體X合併操作的語義如下:

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

持久化提供者不能合併標記的字段LAZY尚未獲取:合併時必須忽略這些字段。

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

因此,除非您傳遞的分離對象具有parentItem作爲惰性引用或null,否則其狀態需要從數據庫中提取以與分離的實例同步。