NHibernate QueryOver将group by放入select中

时间:2014-08-16 10:22:37

标签: c# nhibernate queryover

这可能会被问过几次,我确实找到了一些同一主题的问题(一两个)。然而,这些问题相当陈旧,以及它们仍然没有答案的事实。

基本上我有一个QueryOver(尝试使用Linq到NHibernate获得相同的结果,但对Linq来说显然有点复杂):

PrintJobType printJobType = null;
var test = unitOfWork.Session.QueryOver<PrintJob>()
  .JoinAlias(pj => pj.PrintJobType, () => printJobType)
  .Where(pj => pj.PrintedOn == null)
  .Select(Projections.ProjectionList()
            .Add(Projections.Group(() => printJobType.PriorityWeight))
            .Add(Projections.Group(() => printJobType.ID)))
  .OrderBy(pj => printJobType.PriorityWeight).Desc
  .OrderBy(Projections.Min<PrintJob>(pj => pj.ID)).Asc
  .List<object[]>()
  .Select(x => x[1])
  .Cast<int>();

最大的问题是,对于我的生活,我无法从选择中获得分组,我只想要返回printjob类型的ID,但我似乎无法让它工作。此查询基本上由PrintJobWeight排序,然后是Min Printjob ID秒。

(所以当前查询如下:)

SELECT 
    printjobty1_.PriorityWeight as y0_, printjobty1_.ID as y1_ 
FROM 
    [PrintJob] this_ 
    inner join [PrintJobType] printjobty1_ on this_.PrintJobType_id=printjobty1_.ID 
WHERE 
    this_.PrintedOn is null 
GROUP BY 
    printjobty1_.PriorityWeight, 
    printjobty1_.ID 
ORDER BY 
    printjobty1_.PriorityWeight desc, 
    min(this_.ID) asc

所以我基本上只想返回printjobtype的ID。

作为'奖励',我们真正想要的是选择整个PrintJobType,因为它目前的状态我必须在选择列表之后立即进行.Load(id)调用,这对我来说似乎也是多余但我可以和我一起生活,但目前的结果对我来说似乎效率极低。

在一个完美的世界中,对服务器的查询看起来像:

SELECT 
    printjobty1_.*
FROM 
    [PrintJob] this_ 
    inner join [PrintJobType] printjobty1_ on this_.PrintJobType_id=printjobty1_.ID 
WHERE 
    this_.PrintedOn is null 
GROUP BY 
    printjobty1_.*
ORDER BY 
    printjobty1_.PriorityWeight desc, 
    min(this_.ID) asc

(是的,你不能在group by子句中放置printjobty1 _。*,但它会更快,然后手工写下所有的属性和事物)

NHibernate版本:3.3.1.4000 - SQL Server 2012

1 个答案:

答案 0 :(得分:0)

使用NHibernate的所需解决方案将使用子查询。这样我们就可以首先获得我们需要的ID (分组,排序,过滤),然后使用该ID获得清晰的结果。请在此处观察NHibernate和子查询的强大功能:

我不是100%确定你想要得到什么,但是有一个解决方案草案:

PrintJob printJob = null;
PrintJobType printJobType = null;

// simply this is the place, where we do all the magic
// to select the PrintJob.ID
// I guess that my adjustments would result in the same stuff 
// as in the query above without the grouping
// ... but if not, we still do have a draft of HOW TO
var subQuery = QueryOver.Of<PrintJob>()
    .JoinAlias(pj => pj.PrintJobType, () => printJobType)
    .Where(pj => pj.MiddleName == null)
    .SelectList(l => l
        .Select(pj => pj.ID)
    )
    .OrderBy(() => printJobType.PriorityWeight).Desc
    .OrderBy(pj => pj.ID).Asc
    .Take(1)
    ;

// here we SELECT the clean, root object and its reference... 
// that all will be executed as only ONE Select statement
var result = session.QueryOver<PrintJob>(() => printJob)
    .WithSubquery
        .WhereProperty(() => printJob.ID)
        .In(subQuery)
    .JoinAlias(x => x.PrintJobType, () => printJobType)
    .SingleOrDefault<PrintJob>();

现在,出于某些测试目的,我们可以继续:

// here we say session clear just for the TEST purposes below
session.Clear();

// now, session is closed, no lazy loading, but due to JOIN ALIAS
// the PrintJobType is loaded as well
Assert.IsTrue(result != null);
Assert.IsTrue(result.PrintJobType != null);
Assert.IsTrue(result.PrintJobType.PriorityWeight != null);
相关问题