2011-09-27 96 views
1

我有休眠pojo class A {B b;一些其他的適當性}對於B類,lazy = true。 當我得到對象A時,B沒有被加載,並且hibernate返回它的代理。當我將這個對象傳遞給另一個模塊時,該模塊遍歷A中的每個對象,當它遇到B.getXXX時,它會拋出LazyInitialization異常。在這種特殊情況下,我不想加載B類,因爲它不是必需的。有沒有什麼辦法,當我調用B方法時,它會返回null或將B的代理轉換爲實際對象B,以便模塊不會引發LazyInitialization錯誤。我不能改變B類的getter,setter作爲普通的類並且被其他類使用。從休眠會話中刪除對象

回答

0

感謝您的所有建議。 我的應用程序有分層架構。服務 - >管理器 - >道。經理之後Hibernate會話關閉。其他模塊只能通過服務進行交互。打開休眠會話,直到請求完成不是我的選擇。我也不想打數據庫,因爲B的屬性沒有必要填充。我只想用真實對象替換Hibernate代理,以便任何使用服務的人都不會遇到任何問題。我在 http://svn.rhq-project.org/repos/rhq/branches/HEIKO-EXP/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/HibernateDetachUtility.java 找到一個實用程序,它正是我想要的。它檢查對象並用真實對象替換Hibernate代理。我需要在上述實用程序中自定義以下內容 1.將org.rhq中的classname實例更改爲我的包結構。 2.他們期望pojo身份字段的名稱是「id」。我將其更改爲使用具有javax.persistence.Id註釋的那些屬性。

基本測試與上述更改已完成,它工作正常。我只需要在各種情況下測試整個應用程序,以便它可以在所有情況下工作。

1

如果我理解你的問題,你正在檢索一個對象A與B有懶關聯。但是,這個關聯沒有被初始化,並且你發現其他模塊拋出了異常,因爲實際上使用了B。所以它在某種程度上需要

你想要麼

  • 返回null從到B電話(不可能的,因爲據我所知,除非有這些模塊的一些應用程序特定的行爲,只有你可以知道)或

  • 當這樣的呼叫發生時初始化B。我會盡力幫助你實現這一個。

爲什麼你得到LazyInitializationExceptions的原因是,該獲取B(並沒有初始化)會議已經關閉,所以在這一點上,B實例是沒有用的,在所有。您可以在此應用的一種解決方法是使用OSIV pattern,以便在所有請求範圍中打開相同的Hibernate會話。這是將會獲取A與懶惰B將會初始化B當需要會話。 (如果這些異常都在另一個事務的情況下發生的唯一有效的,那就是,與另一個Hibernate會話,從獲取A的一個不同)

你可以申請另一種選擇是在另一個會話初始化B。例如:

session.update(a.getB()); 

當然,你總是可以強制B初始化與fetchMode.EAGERHibernate.initialize(a.getB())。但是,無條件地加載實例,即使它根本不會被使用。

此外,你可以找到這個問題的答案可能是有用的:hibernate: LazyInitializationException: could not initialize proxy

0

其實,你有幾個選項。

1)使A-> B關係EAGER。

2)當您嘗試在休眠會話已關閉時嘗試啓動代理時,您會收到LazyInitializationExceptions。所以他可能的解決方案是保持Session打開,直到所有的A,B,C ...等對象操作都沒有完成。

3)如果您對WEB環境感興趣,有一種稱爲Open Session的模式。這會使您的Hibernate會話保持打開狀態,直到HTTP請求處於活動狀態。你可以閱讀更多關於here。我認爲這對您閱讀會很有幫助。

0

當會話關閉時,不要將實體發送到其他模塊。

如果這些其他模塊在與會話相同的應用程序域中執行,請在調用模塊時保持會話打開,並在返回時關閉它。

如果這些模塊不在同一個AppDomain中,如果您需要某種序列化來發送對象,或者如果它是異步調用的,我會使用DTO。暴露服務器之外的實體(我不知道這是否是這種情況)是一個不好的做法,原因有幾個。 Ayende Rahien稱之爲Stripper Pattern

+0

我同意將域名暴露給外界不是很好的做法。不幸的是,它是舊代碼,我不能更改方法簽名來使用DTO而不是域。在我的應用程序中,約有98%使用DTO,但導致問題的地方很少。 – dmay