【问题标题】:Converting SQL to QueryOver for getting a row count with group bys将 SQL 转换为 QueryOver 以使用 group bys 获取行数
【发布时间】:2014-05-21 01:32:47
【问题描述】:

我有以下 NHibernate QueryOver 查询:

var query = session.QueryOver<IssuanceReportLogEntity>()
                        .Where(i => i.CustomerId == customer.Id && i.RollbackIssuanceId == null);

if (Parms.StartDate != null) query.Where(i => i.IssuanceDateCreated >= Parms.StartDate);
if (Parms.EndDate != null) query.Where(i => i.IssuanceDateCreated <= Parms.EndDate);
if (Parms.GroupId != null) query.Where(i => i.RecipientGroupId == Parms.GroupId);
if (Parms.ProgramId != null) query.Where(i => i.ProgramId == Parms.ProgramId);

query.Select(
    Projections.Group<IssuanceReportLogEntity>(x => x.RecipientGroupId).WithAlias(() => receiver.RecipientGroupId),
    Projections.Group<IssuanceReportLogEntity>(x => x.RecipientId).WithAlias(() => receiver.RecipientId),
    Projections.Group<IssuanceReportLogEntity>(x => x.RecipientFullName).WithAlias(() => receiver.RecipientFullName),
    Projections.Group<IssuanceReportLogEntity>(x => x.RecipientEmployeeNumber).WithAlias(() => receiver.RecipientEmployeeNumber),
    Projections.Group<IssuanceReportLogEntity>(x => x.RecipientTitle).WithAlias(() => receiver.RecipientTitle),
    Projections.Count<IssuanceReportLogEntity>(x=>x.RecipientGroupId).WithAlias(()=>receiver.RecognitionTotalReceived),
    Projections.Sum<IssuanceReportLogEntity>(x=>x.Points).WithAlias(()=>receiver.TotalPoints));

if (customer.Settings.PointsEnabled)
{
    query.OrderBy(Projections.Sum<IssuanceReportLogEntity>(x => x.Points)).Desc();
}
else
{
    query.OrderBy(Projections.Count<IssuanceReportLogEntity>(x => x.InitiatorId)).Desc();
}

query.TransformUsing(Transformers.AliasToBean<TopReceiver>());

这会生成以下查询(对于数据的选择是正确的):

SELECT TOP (20 /* @p0 */) this_.RecipientGroupId        as y0_,
               this_.RecipientId             as y1_,
               this_.RecipientFullName       as y2_,
               this_.RecipientEmployeeNumber as y3_,
               this_.RecipientTitle          as y4_,
               count(this_.RecipientGroupId) as y5_,
               sum(this_.Points)             as y6_
FROM   [IssuanceReportLog] this_
WHERE  (this_.CustomerId = '30a678bc-264a-4a04-aac4-a3270158929f' /* @p1 */
      and this_.RollbackIssuanceId is null)
     and this_.RecipientGroupId = '2fd9ec20-e870-42f6-b345-a3270158992a' /* @p2 */
GROUP  BY this_.RecipientGroupId,
        this_.RecipientId,
        this_.RecipientFullName,
        this_.RecipientEmployeeNumber,
        this_.RecipientTitle
ORDER  BY sum(this_.Points) desc

我需要做的是弄清楚如何让 NHibernate 在不删除 Group By 的情况下生成行计数,本质上是做类似的事情(注意前面的查询本质上是一个没有 TOP 的子查询):

SELECT COUNT(*) FROM (
SELECT this_.RecipientGroupId        as y0_,
                 this_.RecipientId             as y1_,
                 this_.RecipientFullName       as y2_,
                 this_.RecipientEmployeeNumber as y3_,
                 this_.RecipientTitle          as y4_,
                 count(this_.RecipientGroupId) as y5_,
                 sum(this_.Points)             as y6_
FROM   [IssuanceReportLog] this_
WHERE  (this_.CustomerId = '30a678bc-264a-4a04-aac4-a3270158929f' /* @p1 */
        and this_.RollbackIssuanceId is null)
       and this_.RecipientGroupId = '2fd9ec20-e870-42f6-b345-a3270158992a' /* @p2 */
GROUP  BY this_.RecipientGroupId,
          this_.RecipientId,
          this_.RecipientFullName,
          this_.RecipientEmployeeNumber,
          this_.RecipientTitle
) AS Query

每次我尝试让行计数起作用时,NH 都会删除 GROUP BY。上面的 SQL 按我的预期工作。

关于如何让 NHibernate 吐出该 SQL 的任何想法?

【问题讨论】:

    标签: c# sql sql-server nhibernate


    【解决方案1】:

    NHibernate 中的“标准”方式是创建一个克隆查询:

    var rowCountQuery = query.ToRowCountQuery();
    

    哪个(来自文档):

    克隆QueryOver,删除订单和分页,并投影查询的行数

    但正如你已经(肯定)在这里体验过的那样......这将导致纯粹的查询(因为所有必需的都被删除了,请参阅下面的查询) - 返回错误结果

    SELECT Count(*) FROM   [IssuanceReportLog] -- notwhat needed
    

    解决方案:

    magical sql sn-p 注入到投影中:

    COUNT(*) OVER() AS TotalRowCount

    这将准确返回我们需要的内容。总行数over 我们的查询。我们必须扩展 DTO:

    public class TopReceiver
    {
        ...
        public virtual int TotalRowCount { get; set; }
    

    并像这样调整投影

    query.Select(
        ... // all the GROUP BY statements
        // the total row count
        Projections.SqlProjection(" COUNT(*) OVER() AS TotalRowCount "
                       , new string[] { "TotalRowCount" }
                       , new IType[] { NHibernateUtil.Int32 })
        // count, sum
        Projections.Count<IssuanceReportLogEntity>(x=>x.RecipientGroupId)
                   .WithAlias(()=>receiver.RecognitionTotalReceived),
        Projections.Sum<IssuanceReportLogEntity>(x=>x.Points)
                   .WithAlias(()=>receiver.TotalPoints)
    );
    

    稍后我们甚至可以应用分页,但TotalRowCount 的值仍然是正确的。

    query
        .Skip(100)
        .Take(25)
    

    现在,每个(包括第一个)结果都包含有关总行数的信息。

    var rowCount = list[0].TotalRowCount;
    

    注意:你知道吗? 这实际上是获取row-count 的最有效方法。不仅在 one server-db 往返中,甚至在 one sql 语句执行中...

    【讨论】:

    • 这就像一个冠军!我在 HQL 中看到了这种技术,但在 QueryOver 中没有看到。
    • 很高兴看到这一点 ;) 享受 NHibernate
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 2020-11-12
    • 2019-08-25
    • 1970-01-01
    相关资源
    最近更新 更多