2011-04-26 142 views
5

鑑於以下情形:JPA關係更新

@Entity 
public class A { 
    @OneToMany(mappedBy = "a", cascade = CascadeType.ALL) 
    private List<B> bList; 
} 

@Entity 
public class B { 
    @ManyToOne() 
    @JoinColumn(name = "a_id", referencedColumnName = "id") 
    private A a; 

    @ManyToOne() 
    @JoinColumn(name = "c_id", referencedColumnName = "id") 
    private C c; 
} 

@Entity 
public class C { 
    @OneToMany(mappedBy="c", cascade=CascadeType.ALL, orphanRemoval=true) 
    @CascadeOnDelete // eclipselink specific optimization annotation 
    private List<B> bList; 
} 

換句話說:兩個對象A和對象C包含一個數B的對象。當我刪除一個C對象(技術上,我正在更新一個包含多個C對象並使用orphanremoval的對象)時,我希望刪除所有引用的B對象,該對象按照預期使用當前註釋工作。然而,實體經理似乎並不知道位於緩存中的對象A現在已經失去了一些孩子。如果我有一個A的實例,我當然必須手動更新它的bList,或者做一個新的查詢來更新它,但即使是新提取的A對象也是過時的。重申:

  • C對象被刪除。
  • 拆除級聯到帶有orphanRemoval的B對象。
  • 緩存在實體管理器中的A對象中的bList是未更新
  • 手動清除實體管理器緩存使其檢索正確更新的對象。

這怎麼解決?我期望實體管理者能夠自動更新其持久化上下文,或者在@JoinColumn上創建一個級聯註解,但這兩者似乎都不是這種情況。

編輯:似乎問題在於對象C的bList在對象A的bList更新(因此無法級聯更改)時未得到更新。我不知道爲什麼..但請注意,我在談論持久性上下文,而不是實例化對象。

回答

6

JPA不會爲您執行關係維護,應用程序必須維護它們。這意味着,當您刪除實體時,應用程序負責清除對該實體的任何引用。當它是外鍵關係時很明顯,因爲數據庫約束如果沒有完成,通常會導致異常。在回溯引用的情況下,雖然關係沒有嚴格的數據庫約束,但用戶通常錯誤地認爲JPA會處理它 - 導致緩存損壞。

處理它的方法是刪除對C和B實體的引用。在你的對象模型中,這意味着修復A的bList以刪除Bs。我已經看到這通過實體刪除事件或應用程序代碼處理。由於在這種情況下,A沒有外鍵,所以在刪除發生後(即刷新或提交後),也可以從數據庫中刷新受影響的A實體。

+0

嗯,我總是認爲JPA在幕後處理它,因爲無論我在關係的非擁有方刪除/添加引用,數據庫中的情況都是相同的。謝謝。 – 2011-04-28 14:45:44