Project Collection in NHibernate

后端 未结 1 1872
隐瞒了意图╮
隐瞒了意图╮ 2021-01-24 16:59

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

User
{
    UserGuid,
    IList UserGroups,
}

User userEntity = null;

_se         


        
1条回答
  •  孤城傲影
    2021-01-24 17:44

    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())
        .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/

    0 讨论(0)
提交回复
热议问题