pojo class A { B b ; を休止状態にしています。クラスBのlazy = trueを使用した他のいくつかのプロパティ}。オブジェクトAを取得すると、Bはロードされず、休止状態はそのプロキシを返します。このオブジェクトを別のモジュールに渡すと、そのモジュールは A のすべてのオブジェクトをトラバースし、B.getXXX に遭遇すると LazyInitialization 例外をスローします。この特定のケースでは、クラス B は必須ではないため、ロードしたくありません。モジュールが LazyInitialization エラーをスローしないように、B でメソッドを呼び出すときに null を返すか、B のプロキシを実際のオブジェクト B に変換する方法はありますか。クラスBのゲッター、セッターは共通のクラスであり、他の多くのクラスで使用されるため、変更できません。
4 に答える
あなたの質問を理解すると、Bへの遅延関連付けを持つオブジェクトAを取得しています。ただし、この関連付けは初期化されておらず、Bが実際に使用されているため、他のモジュールが例外をスローしていることがわかります。したがって、何らかの方法で必要になります。
あなたはどちらかをしたい
null
呼び出しから戻るB
(私が知る限り、あなただけが認識できるモジュールにアプリケーション固有の動作がない限り、不可能です)またはB
そのような呼び出しが発生したときに初期化します。私はあなたがこれを実装するのを手伝おうとします。
取得している理由LazyInitializationExceptions
は、フェッチした(そして初期化していない)セッションB
がすでに閉じられているためです。したがって、この時点では、のインスタンスはB
まったく役に立ちません。ここで適用できる回避策の1つは、OSIVパターンを使用して、すべてのリクエストスコープで同じHibernateセッションを開くことです。A
これは、怠惰にフェッチしB
、必要に応じて初期化するセッションですB
。
適用できる別のオプションはB
、別のセッションで初期化することです(これらの例外が別のトランザクションのコンテキストで発生している場合、つまり、フェッチしたセッションとは異なる別のHibernateセッションが開いている場合にのみ有効ですA
)。例えば:
session.update(a.getB());
もちろん、いつでもB
withfetchMode.EAGER
またはの初期化を強制することができますHibernate.initialize(a.getB())
。ただし、インスタンスがまったく使用されない場合でも、無条件にインスタンスが読み込まれます。
また、この質問への回答が役立つ場合があります:hibernate:LazyInitializationException:プロキシを初期化できませんでした
セッションが閉じられているときは、エンティティを他のモジュールに送信しないでください。
これらの他のモジュールがセッションと同じアプリケーションドメインで実行されている場合は、モジュールを呼び出すときにセッションを開いたままにし、戻ったときにセッションを閉じます。
これらのモジュールが同じAppDomainにない場合、オブジェクトを送信するために何らかのシリアル化が必要な場合、または非同期で呼び出される場合は、DTOを使用します。サーバーの外部にエンティティを公開すること(これがここに当てはまるかどうかはわかりません)は、いくつかの理由から悪い習慣です。AyendeRahienはそれをストリッパーパターンと呼んでいます。
実際には、いくつかのオプションがあります。
1) A->B 関係を EAGER にする。
2)LazyInitializationExceptions
休止状態のセッションがすでに閉じている間にプロキシを開始しようとすると、取得されます。したがって、可能な解決策は、A、B、C ...などのオブジェクト操作がすべて完了するまでセッションを開いたままにすることです。
3) WEB環境にこだわるならOpen Sessionというパターンが視野にある。HTTPリクエストが有効になるまでHibernateセッションを開いたままにします。
詳細については、こちらをご覧ください。読んでいただけると助かると思います。
ご提案いただきありがとうございます。私のアプリケーションには階層化されたアーキテクチャがあります。サービス -> マネージャー -> ダオ。マネージャーの後に Hibernate セッションが閉じます。他のモジュールは、サービスを介してのみ対話します。リクエストが完了するまで休止状態のセッションを開くことは、私にとってオプションではありません。B のプロパティを入力する必要がないため、データベースにもアクセスしたくありません。サービスを使用している人が問題に直面しないように、休止状態のプロキシを実際のオブジェクトに置き換えたいだけです。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 これはまさに私が望むことをします。オブジェクトを検査し、休止状態のプロキシを実際のオブジェクトに置き換えます。上記のユーティリティ 1 で次のことをカスタマイズする必要があります。classname のインスタンスを org.rhq からパッケージ構造に変更します。2. 彼らは、pojo の ID フィールドの名前が「id」であることを期待しています。javax.persistence.Id のアノテーションを持つプロパティを使用するように変更します。
上記の変更を加えた基本的なテストは完了しており、正常に動作しています。すべてのシナリオで動作するように、さまざまなシナリオでアプリケーション全体をテストする必要があります。