在NHibernate中加载没有重复的多级集合

dst*_*stj 3 nhibernate nhibernate-criteria

我的问题与这个问题非常相似(没有真正回答):Nhibernate:二级收集中的明显结果

我有这个对象模型:

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

   class EntityB
   {
       ... does NOT reference its parent EntityA...
       IList<EntityC> CList { get; protected set; }
   }
Run Code Online (Sandbox Code Playgroud)

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

我想通过执行类似以下三个SQL查询的内容来完全加载集合,以避免笛卡尔连接:

 SELECT id, ... FROM EntityA;
 SELECT id, idA, ... FROM EntityB;
 SELECT id, idB, ... FROM EntityC;
Run Code Online (Sandbox Code Playgroud)

有了它,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();
        }
     }
Run Code Online (Sandbox Code Playgroud)

Gob*_*lin 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();
Run Code Online (Sandbox Code Playgroud)

这应该激发你提到的三个选择.它可能看起来有点令人费解,但它正在利用会话的第一级缓存,这可确保第一个集合中的所有实体在执行时都使用加载的集合进行更新.

此外,您不需要支付第二次和第三次查询可能具有的任何复杂查询逻辑的惩罚.数据库应该使用第二个查询的主索引(甚至可能根据您的设置进行群集)和用于极低成本查询的连接的外键.