Project Collection in NHibernate

落爺英雄遲暮 提交于 2019-12-02 11:06:28

问题


Is it possible that I can project collection in NHibernate? For Example:

User
{
    UserGuid,
    IList<Groups> UserGroups,
}

User userEntity = null;

_session
    .StatefulSession.QueryOver(() => userEntity)
    .SelectList(list => list
         .Select(x => x.UserGuid).WithAlias(() => userEntity.UserGuid)

         //How can I project group collection here?
         .Select(x => x.Groups).WithAlias(() => userEntity.Groups)
    )
    .TransformUsing(Transformers.AliasToBean<UserEntity>())
    .List();

回答1:


We have to thing about projection as a single SELECT clause. What we would be able to do with it on a DB side, we can mimic with QueryOver. So, in this case, we can join User and Group, and project few properties from User and few from Group. The best target would be some DTO...

The syntax could be like this:

ResultDTO resultDTO = null; // the target to be returned
Group groupEntity = null;
User userEntity = null;

_session.StatefulSession
    .QueryOver(() => userEntity)
    .JoinAlias(() => userEntity.Groups, () => groupEntity)
    .SelectList(list => list
        .Select(x => x.UserGuid).WithAlias(() => resultDTO.UserGuid)
        // more about User - targeting the ResultDTO
        ...
        // almost the same for Group properties
        .Select(x => groupEntity.Name).WithAlias(() => resultDTO.GroupName)
        ..
    )
    .TransformUsing(Transformers.AliasToBean<ResultDTO >())
    .List();

But there are some issues arround, which in fact effectively disallow this approach. We will reach the Cartesian product, because each row of a User will be multiplied as many times, as many Groups it does have.

Row 1 - User A - Group A
Row 2 - User A - Group B // two rows for a user A
Row 3 - User B - Group B
Row 4 - User B - Group C

One way to solve it, is to skip the SelectList() (do not use projections) and ask NHiberante to use different transformation:

_session.StatefulSession
    .QueryOver(() => userEntity)
    .JoinAlias(() => userEntity.Groups, () => groupEntity)
    .TransformUsing(Transformers.DistinctRootEntity)
    .List();

Nice, one would say, but it is wrong again. No effective paging is possible, because the effect of more rows for each User still remains. So, if we would say Take(2), we will get only User A. The reason is hidden in fact, that the narrowing is done expost, in memory, on .NET/Application tier side - not in DB

Suggestion: Do not use any joins among one-to-many relations. Use the separated queries with conjunction of powerful NHibernate feature: 19.1.5. Using batch fetching

Please, see also:

  • NHibernate QueryOver with Fetch resulting multiple sql queries and db hits
  • Is this the right way to eager load child collections in NHibernate
  • https://stackoverflow.com/questions/18419988/


来源:https://stackoverflow.com/questions/24517403/project-collection-in-nhibernate

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