NHibernate QueryOver Subquery

前端 未结 2 991
滥情空心
滥情空心 2021-01-04 18:08

I\'ve looked at the similar questions, but can\'t find a simple explanation. I could have missed it, but I promise I looked. Actually I can\'t even find the documentation ot

相关标签:
2条回答
  • 2021-01-04 18:46

    Well, hashed at this some more, and while I don't like one part of the results, it does work:

    var distinctProgIdsSubQuery = QueryOver.Of<Program>().
    JoinQueryOver<Topic>(p => p.Topics).
    WhereRestrictionOn(pt => pt.Id).IsIn(topicIds)
    .Select(Projections.Distinct(Projections.Property<Program>(p => p.Id)));
    
    
    ProgramDTO pDTO = null;
    var progQuery = Session.QueryOver<Program>()
        .WithSubquery.WhereProperty(p => p.Id).In(distinctProgIdsSubQuery)
        .SelectList(list => list
            .Select(program => program.Id).WithAlias(() => pDTO.Id)
            .Select(...)
            )
        .TransformUsing(Transformers.AliasToBean(typeof(ProgramDTO)));
    
    
    return progQuery.List<ProgramDTO>();
    

    This produces

    SELECT this_.ProgramId as y0_, ...
    FROM Programs this_ 
    WHERE this_.ProgramId in (
            SELECT distinct this_0_.ProgramId as y0_ 
            FROM
                Programs this_0_ 
            inner join
                Programs_Topics topics3_ 
                    on this_0_.ProgramId=topics3_.ProgramId 
            inner join
                Topics topic1_ 
                    on topics3_.TopicId=topic1_.TopicId 
            WHERE
                topic1_.TopicId in (
                    @p1, @p2, ...
                )
        ) 
    

    This may be a limitation of NH, but there's no need to join the Programs table in the subquery. I tried to write this from the other direction -- that is, to create a QueryOver.Of<Topic>(), but I could not figure out how to select the program IDs at the end -- select was only giving me the TopicIds, and even then the query was still joining all three tables.

    I'm not sure if MS-SQL's query optimizer will avoid the useless join or not, but it would be nice if we didn't have to rely on it.

    For now though, this works, and hopefully someone else has fewer headaches than I did trying to figure this out.

    0 讨论(0)
  • 2021-01-04 18:59

    You need to create a dettached query containing the Id's and then use this sub query with the main query.

    I have pasted an example here so you will need to replace the relevant bits with your class names etc.

    First the set up (you can ignore this bit):-

    public class TestDto {
      public long Id { get; set; }
      public string Name { get; set; }
    }
    ...
    TestDto dto = null;
    var ids = new List<int> { 1,2,5,7 };
    

    Now the dettached query:-

    var idSubQuery = QueryOver.Of<CmsRegionContent>()
      .WhereRestrictionOn(w => w.Id).IsIn(ids)
      .Select(Projections.Distinct(Projections.Property<CmsPage>(s => s.Id)));
    

    And the final bit is to put it all together:-

    var query = Session.QueryOver<CmsPage>()
        .JoinQueryOver<CmsRegionContent>(l => l.CmsRegionContentList)
        .WithSubquery
        .WhereProperty(m => m.Id)
        .In(idSubQuery)
        .SelectList(list => list
                                .Select(p => p.Id).WithAlias(() => dto.Id)
                                .Select(p => p.PageName).WithAlias(() => dto.Name)
                    )
                    .TransformUsing(Transformers.AliasToBean(typeof(TestDto)));
    
    var model = query.List<TestDto>();
    

    This will create the following SQL:-

    SELECT
         this_.Id as y0_,
         this_.PageName as y1_ 
    FROM cmspage this_ inner join cmsregioncontent cmsregionc1_ 
      on this_.Id=cmsregionc1_.PageId 
    WHERE cmsregionc1_.Id in (
        SELECT
             distinct this_0_.Id as y0_ 
        FROM cmsregioncontent this_0_ 
        WHERE this_0_.Id in (
            1 /* ?p0 */,
             2 /* ?p1 */,
             5 /* ?p2 */,
             7 /* ?p3 */)
        )
    

    Hopefully you will be able to follow this with your class/property names.

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