2012-01-05 14 views
1

私のウェブページにはいくつかのドロップダウンがあります。これらはリンクされており、双方向リンクで同様のクラス構造を持っています。nhibernate3 query - コレクションを含むコレクション

つまり、クラスAlphaには、クラスBetaのリストがあり、これにはチャーリークラスのリストがあります。各クラスのベータ版にはアルファ(それが属するもの)の独自のリストがあり、各クラスのチャーリーには独自のベータリストがあります。

私は、流暢なnhibernateとautomappingsでNHibernate 3を使用しています。

今すぐ。私が単純に実行する場合

session.CreateCriteria<Alpha>().SetMaxResults(1000).List<Alpha>(); 

私はコレクションをループするときにN + 1の問題が発生します。

私はそれ以下のSQLの参照方法は、すべてのことがデータベース

select top 1000 * from Alpha 
select top 1000 * from Beta 
select top 1000 * from Charlie 
select * from Alpha2Beta 
select * from Beta2Charlie 

しかし、どのようにこれが機能するために、私は、クエリを記述しないために照会する必要があります?

+0

アルファとベータ、ベータとチャーリーの間に双方向の関係があります。どのようにこれらの3つのテーブルのみをクエリできますか?これを達成するためのテーブルをリンクする必要があります... –

+0

ああ愚かな私、あなたは絶対に正しいです!テキストを更新します – Ivar

+0

ステートレスセッションを使用しているようです。 StatelessSessionにはキャッシュがありません。ステートレスセッションのオブジェクトは遅延ロードできません。つまり、コンポーネントをプリフェッチして合成クエリを実行することはできません。この場合、クエリで.Fetch()を使用して、Alpha2BetaとBeta2Charlieのサブオブジェクトを熱心に読み込む必要があります。まだいくつかの重複がありますが、N + 1ほど悪くはありません。 – Origin

答えて

0

基準を使用している場合は、Dyanmic Fetchingメソッド呼び出しを含める必要があります。

+0

私が知る限り、複数のコレクションに対して動的なフェッチを使用することはできません。このようにして複数の関連エンティティと1つのコレクションだけをフェッチできます。 –

1

アイドンがブログで示した素晴らしいトリックがあります。この問題を回避するために私のBLを変更することにしたので、私は個人的に試したことがないので、塩の穀物でこれを取る。

NHibernate Futuresを使用して、別々にコレクションをロードし、NHibernateにエンティティを接続させることができるはずです。明るい被写体ではないので、あなたはread his blog postが良いです。

+0

ファッションの後には機能しますが、すべてのAlphaとすべてのBetaにクエリを実行しても、NHはAlpha <->ベータの関連付けをクエリする必要があるため、SELECT N + 1を実行します。 – Rytmis

+0

もう一度、リソースを指摘してみませんでしたが、AlphaとBetaの両方をロードしてテーブルをジョインすると、別のN + 1が必要になるのはなぜですか?私はすべてをロードするだけではうまくいくとは言いませんが、そうでない場合は、サポートされていないためです。実装できないからではありません。もちろん、これにはいくつかのクリエイティブマッピングが必要です:)(結合テーブルのマッピング) –

+0

アルファとベータを照会すると、アイデンティティマップ(L1キャッシュ)は、アソシエーションにアクセスするときにベータ版をロードする必要はありません。アルファ。しかし、クエリにロードされないものは関連テーブルの内容なので、関連付けにヒットしたときの動作は、「SELECT FROM Alpha_to_Beta INNER JOIN Beta ...」ではなく「SELECT FROM Alpha_to_Beta WHERE Alpha_Id = n」です。つまり、関連がまだロードされていない場合、エンティティ自身がプリロードされるのを助けません。それは私の意見を明確にしていますか? :-) – Rytmis

0

私が知る限り、ジョインフェッチの場合と同じように、クエリレベルでクエリでこれを手助けする方法はありません。あなたはマッピングを変更し、デフォルトは「サブクエリ」する団体のためのフェッチモードを設定する場合は、あなたは愉快に驚くかもしれません:Hibernate Documentation(NHibernateのと同様に動作)から

コレクションでfetch = "subselect"を指定すると、この コレクションを2番目のSELECT(レイジーまたは非遅延のいずれか)にロードするだけでなく、ロードしたすべての "所有"エンティティの他のすべてのコレクション 最初のSELECT。これは、これが意味することは、第1の関連付けが必要な場合に、NHibernateのは、代わりにロード1つの協会、あなたがルートエンティティを取得するために使用されるクエリを思い出すだろうということです

「並行して複数のコレクションを取得 するのに特に有用ですクエリによって返されたルートエンティティタイプのすべてのインスタンスのアソシエーションデータをロードします。

つまり、1Kエンティティをロードしていて、アソシエーションに2つ以上のレコードがあるとします。おそらくちょうど(SELECT N + 1)^ 2から「データベース全体をメモリにロードした聖なるくそ」に行くでしょう。;-)

(これを実行し、Alphaリストを読み込むシナリオがありますが、単一のAlphaに関連付けられたベータだけが必要な場合は、まだそれらのすべてを読み込み、それについて何もできません。実際には、私はこれが非常にまれなシナリオであることを発見しました。したがって、通常、サブセレクトフェッチは私によく合います。)

関連する問題