3

私の質問はこれに非常に似ています(実際には答えられませんでした):Nhibernate:第2レベルのコレクションで明確な結果

私はこのオブジェクトモデルを持っています:

   class EntityA
   {
        ...
        IList<EntityB> BList { get; protected set; }
        ...
   }

   class EntityB
   {
       ... does NOT reference its parent EntityA...
       IList<EntityC> CList { get; protected set; }
   }

それらは1対多の関係です。EntityBとCには、その親オブジェクトへのオブジェクト参照がありません。

デカルト結合を回避するために、次の3つのSQLクエリのようなものを実行して、コレクションを完全にロードしたいと思います。

 SELECT id, ... FROM EntityA;
 SELECT id, idA, ... FROM EntityB;
 SELECT id, idB, ... FROM EntityC;

これにより、DALはオブジェクトを適切に埋めるためのすべての情報を取得します。ただし、EntityBはその親が誰であるかを認識していないためコレクションの適切な入力を処理するのはnHibernateである必要があります。

できますか?


デカルト積を使用してこの回避策を実行できますが、コレクションセッターを提供するようにモデルを変更する必要があります。これは、DALに関する技術的な問題のパッチとしての資格があります。

     ICriteria criteria = session.CreateCriteria<EntityA>()
                         .SetFetchMode("BList", FetchMode.Join)
                         .SetFetchMode("BList.CList", FetchMode.Join)
                         .SetResultTransformer(new DistinctRootEntityResultTransformer());

     IList<EntityA> listA = criteria.List<EntityA>();

     foreach (EntityA objA in listA) {
        objA.BList = objA.BList.Distinct().ToList();
        foreach (EntityB objB in objB.BList) {
           objB.CList = objB.CList.Distinct().ToList();
        }
     }
4

1 に答える 1

5

この構文を試しましたか:

var entities = session.QueryOver<EntityA>().Where(...).List();
var entityIds = entities.Select(e => e.Id).ToArray();
session.QueryOver<EntityA>()
    .WhereRestrictionOn(a => a.Id)
    .IsIn(entityIds)
    .Fetch(e => e.BList).Eager
    .List();

var bEntityIds = entities
    .SelectMany(e => e.BList)
    .Select(b => b.Id)
    .ToArray();

session.QueryOver<EntityB>()
    .WhereRestrictionOn(b => b.Id)
    .IsIn(bEntityIds).Fetch(e => e.CList).Eager
    .List();

これにより、言及した3つの選択が実行されます。少し複雑に見えるかもしれませんが、セッションの第1レベルのキャッシュを利用しているため、最初のコレクションのすべてのエンティティが、実行時にロードされたコレクションで更新されます。

また、2番目と3番目のクエリに対して配置している複雑なクエリロジックのペナルティを支払う必要はありません。DBは、2番目のクエリにプライマリインデックス(設定によってはクラスター化されている場合もあります)を使用し、非常に低コストのクエリの結合には外部キーを使用する必要があります。

于 2011-09-30T20:18:41.157 に答える