Loading multi-level collections without duplicates in NHibernate

心不动则不痛 提交于 2019-12-23 19:13:22

问题


My question is very similar to this one (that wasn't really answered): Nhibernate: distinct results in second level Collection

I have this object model:

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

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

They are One-to-Many relations. EntityB and C do not have an object reference to its parent object.

I'd like to fully load the collections by performing something like the following three SQL queries to avoid to Cartesian join:

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

With that, the DAL has all the information to properly fill the objects. But since EntityB is not aware of who its parent is, it has to be nHibernate who takes care of filling the collections properly.

Can it be done ??


I could do this workaround with the Cartesian Product, but it requires modifying my model to provide a collection setter and that qualifies as a patch for a technical problem with the DAL in my mind.

     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();
        }
     }

回答1:


Have you tried this syntax:

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();

This should fire the three selects that you mention. It might seem a wee bit convoluted, but it is taking advantage of the session's first level cache, which ensures that all the entities in the first collection is updated with the loaded collections as they are executed.

Also, you do not pay the penalty of whatever complex query-logic you may have in place for the second and third query. The DB should use the primary index for the second query (maybe even clustered depending on you settings) and a foreign key for the join for extremely low-cost queries.



来源:https://stackoverflow.com/questions/7614661/loading-multi-level-collections-without-duplicates-in-nhibernate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!