Hibernate:クライアント/サーバーアプリケーションの開発で遅延初期化を使用する

Hibernateを使用して開発されたアプリケーションのドメインを設計するとき、開発者は、関連するドメインのコレクションに対応するドメインプロパティをすぐに初期化する(FetchType = EAGER)か、それらにアクセスするときにのみこれを行う(FetchType = LAZY)かを選択する必要があります。 実際、サブジェクト領域にオブジェクト間のリレーションの複雑な構造がある場合、FetchType = EAGERの場合のように、1つのオブジェクトのためにデータベースの半分をロードするという選択が既に行われています。 したがって、コレクションの場合の遅延初期化は、関連オブジェクトを初期化するための最も好ましい戦略です。



ただし、すべてがそれほど単純ではありません。 遅延初期化は、JDK Dynamic ProxyまたはCGLIBライブラリを使用してプロキシオブジェクトを作成することにより実現されます。 どちらの場合も、適切なgetメソッドのプロキシは、必要なデータを取得するためにHibernateセッションにアクセスすることになります。 後者は、Hibernateセッションがある場合にのみ、オブジェクトの遅延プロパティへのアクセスが可能になることを意味します。 それ以外の場合、オブジェクトプロパティを取得しようとすると、忘れられない例外「LazyInitializationException:プロキシを初期化できませんでした-所有するセッションが閉じられました」が発生します。





開いているセッションを手元に置くことは常に可能なこととはほど遠いことは明らかであり、これは不便をもたらします。 したがって、たとえば、MVCアプリケーションテンプレートで遅延初期化でドメインを使用するには、「 OpenSessionInView 」メソッドに頼らなければなりません。その本質は、リクエスト処理の開始時にセッションを開き、終了時に閉じることを保証するフィルターを作成することです



しかし、アップロードされたデータを含むドメインをHibernateセッション外で使用する必要がある場合はどうでしょうか? たとえば、クライアント/サーバーアーキテクチャの場合、サーバーはいつドメインをクライアントに転送する必要がありますか? もちろん、一般的な場合にデータベースについて何も知らないという理由だけで、クライアント側でセッションを開くという話はありません。 私の意見では、状況から抜け出す唯一の方法は、ドメインオブジェクトを「ドロップ」し、サーバーからクライアントに転送する前に必要なデータでそれらを初期化することです。



アプリケーションのサーバー側が3つのレイヤーで構成されていると想像してください。



ドメインクラス自体は、サーバーとクライアントの両方で使用できます(一般に論理的です)。



このシナリオでは、ビジネスロジックレイヤーはHibernateセッション内でドメインプロキシを簡単に使用できます。 この場合のサービス層の役割は、クライアントのビジネスロジック層とデータ構成から必要なデータを取得すること、つまり特定の深さと詳細をコピーすることによりドメインクラスに基づいてDTOオブジェクトを作成することに限定されます。



問題は、この「デプロキシ」を実行する方法だけです。 原則として、これはHibernate自体を使用して実行できます。



public static <T> T initializeAndUnproxy(T entity) {

if (entity == null ) {

throw new

NullPointerException( "Entity passed for initialization is null" );

}



Hibernate.initialize(entity);

if (entity instanceof HibernateProxy) {

entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()

.getImplementation();

}

return entity;

}



* This source code was highlighted with Source Code Highlighter .








このようなアプローチは、特定のオブジェクトのすべてのコレクションを初期化し、プロキシから「取得」します。 ただし、いくつかの欠点があります。行内のすべてのコレクションが初期化され、親オブジェクトのみが非プロキシ化されます(少なくとも、非プロキシ化時にオブジェクトの接続グラフをどの程度下げる必要があるかが不明です)。



この状況での解決策は、同じクラスの新しいオブジェクトを作成し、Hibernate基本クラスに対応するプロパティを初期化することにより、ドメインのプロキシ解除を実行する小さなユーティリティクラスを作成することです。 オブジェクトの他のすべてのプロパティは、必要に応じてサービス層によって初期化されます。



私は、このアプローチが最適である、または唯一の正しいアプローチであるとは言いません。 それ以外の問題を解決する方法について何か提案があれば、私はそれらを聞いてうれしいです。



All Articles