3

我的问题与这个问题非常相似(没有真正回答):Nhibernate: distinct results in second level Collection

我有这个对象模型:

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

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

它们是一对多的关系。EntityB 和 C没有对其父对象的对象引用。

我想通过执行以下三个 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();

这应该会触发您提到的三个选择。它可能看起来有点复杂,但它利用了会话的一级缓存,这确保了第一个集合中的所有实体在执行时都使用加载的集合进行更新。

此外,您不必为第二个和第三个查询可能存在的任何复杂查询逻辑付出代价。数据库应该将主索引用于第二个查询(甚至可能根据您的设置进行集群)和用于极低成本查询的连接的外键。

于 2011-09-30T20:18:41.157 回答