ActiveRecord を使用した nHibernate での遅延ロードされたエンティティの積極的なロード
-
22-08-2019 - |
質問
私は、さまざまな集合ルートのセットを含む豊富なオブジェクト モデルを含むプロジェクトに取り組んでいます。
私たちが使用しているのは、 城 スタック (ActiveRecord を使用した nHibernate までのモノレール)。
集約ルートを遅延としてマークしました。 [ActiveRecord(Lazy = true)]
また、オブジェクト グラフを積極的にフェッチするために、リポジトリ上にカスタマイズされた「eager」ルーチンがあります。HQL を使用して、ルートの子コレクションからの熱心なフェッチを定義します。
例えばもし Account
は集約ルート (遅延ロードとしてマークされている) です。熱心にフェッチします。 Account .. Order .. Product
完全なグラフのエンティティ。
したがって、これまでのところ驚くべきことではありません(できれば)。
上記の例では、Product もマークされているとします。 [ActiveRecord(Lazy = true)]
, 、これにより、HQL の熱心なフェッチ ディレクティブが停止されるようです。
遅延ロードされた子オブジェクトの積極的なフェッチを強制する方法を知っている人はいますか ??
乾杯イアン
アップデート:
ここに HQL の例を示します。以下の「me.yahoo.com/../1」の例を使用して、IMuliQuery を使用して、多対多の関係をフェッチするときに N+1 の依存関係を再愛しています。また、多対多のマッピング クラスも明示的に使用しています。結果として、HQL は次のようになります。
from Account a 'm eager loading the graph
inner join fetch a.AccountsOrders ao
inner join fetch ao.Order
from Account a 'm eager loading the graph
inner join fetch a.AccountAddresses aa
inner join fetch aa.Address ad
where a.ID = ?
...これにより、2 つの SQL ステートメントが実行され、必要な最小限の行セットが返され、これを単一のオブジェクト グラフに解決できます。ニース。
しかし...たとえば、 Address
遅延ロードとしてマークされていました (そして Order
ではありませんでした)、アクセスしています Order
それ以上の SQL ステートメントはトリガーされませんが、アクセス Address
どちらも熱心にロードされているにもかかわらず、そうします。
では、なぜエンティティは遅延ロードされないのでしょうか Address
, 、上記のステートメントによって熱心に取得されましたか?
解決
なぜ熱心な行動を望むのですか?
ActiveRecord のすべての Relationship 属性には、関連オブジェクトを遅延ロードするように ActiveRecord に指示する 'Lazy=' パラメータがあります。BelongsTo を除くすべて。BelongsTo は、依存オブジェクトの ActiveRecord 属性に Lazy=true があるかどうかを確認し、選択または結合を実行する代わりにオブジェクトのプロキシを作成します。
遅延読み込みが機能するには、クラス インスタンスのすべてのメソッドとプロパティが仮想としてマークされている必要があります。これにより、ActiveRecord が動的プロキシ クラスを構築できるようになります。
パフォーマンスのために完全なグラフを取得するのは良い考えのように聞こえるかもしれませんが、実際にはおそらく遅くなります。理由は 3 つあります。
1.) BelongsTo には、関連オブジェクトを取得する方法を定義する Fetch オプションがあります。FetchEnum.Join は AR に結合の使用を強制します。FetchEnum。Select では、AR はオブジェクトごとに個別の選択ステートメントを使用するように強制されます。結合は遅いですが、個別選択に切り替えることでパフォーマンスが 10 倍向上しました。Lazy=true + FetchEnum.Select と Eager の間のクライアント コードには実質的な違いはありません。
2.) Hibernate はキャッシュを行います。オブジェクトがすでにセッションまたはレベル 2 キャッシュにキャッシュされている場合は、そこからロードすることができ、余分な作業を回避できます。
3.) オブジェクト グラフの一部を参照しなかった場合、遅延読み込みの利点が失われます。また必要以上に仕事をすることになります。
他のヒント
Account.Order.Product エンティティに対して「内部結合フェッチ」を実行します。したがって、次のようなものの代わりに (これはおそらくすでに持っているものです):
"from Account a inner join fetch a.Order where a.ID = ?"
Order.Product も取得するように指示します。
"from Account a inner join fetch a.Order inner join fetch a.Order.Product where a.ID = ?"
「NHibernate の動作」(225 ページ) より:
Hibernate では現在、積極的に取得できるコレクションは 1 つだけに制限されています。
これで、アドレスを取得するための 2 番目のクエリが説明できるかもしれません。