【问题标题】:ToRowCountQuery seems to ignore groupingsToRowCountQuery 似乎忽略了分组
【发布时间】:2011-12-22 05:08:54
【问题描述】:

我正在尝试从常规查询创建行计数查询,但生成的 SQL 似乎缺少 GROUP BY 导致计数错误。有谁知道我做错了什么。

首先是查询:

var query = Session.QueryOver<InkoopFactuurListItem>()
    .Where(i => i.KlantId == Klant.Id)
    .AndRestrictionOn(i => i.Status).IsIn(statussen)
    .SelectList(list => list
        .SelectGroup(h => h.Id).WithAlias(() => dto.Id)
        .SelectGroup(h => h.Banknummer).WithAlias(() => dto.Banknummer)
        .SelectGroup(h => h.CrediteurNaam).WithAlias(() => dto.CrediteurNaam)
        .SelectGroup(h => h.DienstType).WithAlias(() => dto.DienstType)
        .SelectGroup(h => h.DocumentId).WithAlias(() => dto.DocumentId)
        .SelectGroup(h => h.DocumentNaam).WithAlias(() => dto.DocumentNaam)
        .SelectGroup(h => h.Factuurbedrag).WithAlias(() => dto.Factuurbedrag)
        .SelectGroup(h => h.Klantnummer).WithAlias(() => dto.Klantnummer)
        .SelectGroup(h => h.Factuurbtw).WithAlias(() => dto.Factuurbtw)
        .SelectGroup(h => h.FactuurDatum).WithAlias(() => dto.FactuurDatum)
        .SelectGroup(h => h.Factuurnummer).WithAlias(() => dto.Factuurnummer)
        .SelectGroup(h => h.IMSNummer).WithAlias(() => dto.IMSNummer)
        .SelectGroup(h => h.KlantId).WithAlias(() => dto.KlantId)
        .SelectGroup(h => h.Soortfactuur).WithAlias(() => dto.Soortfactuur)
        .SelectGroup(h => h.Status).WithAlias(() => dto.Status)
        .SelectGroup(h => h.VerwerktOp).WithAlias(() => dto.VerwerktOp)
        .SelectMin(h => h.Van).WithAlias(() => dto.Van)
        .SelectMax(h => h.Tot).WithAlias(() => dto.Tot))
    .TransformUsing(Transformers.AliasToBean<InkoopFactuurListItem>());

var rowcount = query.ToRowCountQuery().FutureValue<int>();

IEnumerable<InkoopFactuurListItem> results;
if (command.Page > 0 && command.PageSize > 0)
{
    results = query
        .Skip((command.Page - 1) * command.PageSize)
        .Take(command.PageSize).Future<InkoopFactuurListItem>();
}
else
{
    results = query
        .Take(command.PageSize)
        .Future<InkoopFactuurListItem>();
}

count = rowcount.Value;

生成的 SQL:

SELECT count(*) as y0_ 
FROM vwInkoopFactuurListItem this_ 
WHERE this_.KlantId = @p0 and this_.Status in (@p1, @p2, @p3, @p4, @p5);

SELECT TOP (@p6) y0_, y1_, y2_, y3_, y4_, y5_, y6_, y7_, y8_, y9_, y10_, y11_, y12_, y13_, y14_, y15_, y16_, y17_ 
FROM (
    SELECT this_.InkoopFactuurId as y0_, this_.Banknummer as y1_, this_.CrediteurNaam as y2_, this_.DienstType as y3_, this_.DocumentId as y4_, this_.DocumentNaam as y5_, this_.Factuurbedrag as y6_, this_.Klantnummer as y7_, this_.Factuurbtw as y8_, this_.FactuurDatum as y9_, this_.Factuurnummer as y10_, this_.IMSNummer as y11_, this_.KlantId as y12_, this_.Soortfactuur as y13_, this_.Status as y14_, this_.VerwerktOp as y15_, min(this_.Van) as y16_, max(this_.Tot) as y17_,
    ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row
    FROM vwInkoopFactuurListItem this_
    WHERE this_.KlantId = @p8 and this_.Status in (@p9, @p10, @p11, @p12, @p13)
    GROUP BY this_.InkoopFactuurId, this_.Banknummer, this_.CrediteurNaam, this_.DienstType, this_.DocumentId, this_.DocumentNaam, this_.Factuurbedrag, this_.Klantnummer, this_.Factuurbtw, this_.FactuurDatum, this_.Factuurnummer, this_.IMSNummer, this_.KlantId, this_.Soortfactuur, this_.Status, this_.VerwerktOp
) as query 
WHERE query.__hibernate_sort_row > @p7
ORDER BY query.__hibernate_sort_row; ;@p0 = 1 [Type: Int64 (0)], @p1 = 'OverigMatchingInkoop' [Type: String (255)], @p2 = 'OverigMatchingVerkoop' [Type: String (255)], @p3 = 'Overig' [Type: String (255)], @p4 = 'Geboekt' [Type: String (255)], @p5 = 'Geexporteerd' [Type: String (255)], @p6 = 10 [Type: Int32 (0)], @p7 = 284590 [Type: Int32 (0)], @p8 = 1 [Type: Int64 (0)], @p9 = 'OverigMatchingInkoop' [Type: String (255)], @p10 = 'OverigMatchingVerkoop' [Type: String (255)], @p11 = 'Overig' [Type: String (255)], @p12 = 'Geboekt' [Type: String (255)], @p13 = 'Geexporteerd' [Type: String (255)]

那么行计数查询中的 GROUP BY 在哪里?

更新 事实证明,ToRowCountQuery 从原始查询中去除了选择和分组。那么我该怎么做这样的事情:

select count(*)
from (... query ...)

Firo 的答案似乎是朝着正确方向迈出的一步,但我不能使用 CountDistinct,因为我需要对所有字段进行计数,包括选择列表中显示的最小/最大字段。除此之外,CountDistinct 不采用 IProjection 作为参数:

//
// Summary:
//     A distinct property value count
public static CountProjection CountDistinct(Expression<Func<object>> expression);
//
// Summary:
//     A distinct property value count
public static CountProjection CountDistinct<T>(Expression<Func<T, object>> expression);
//
// Summary:
//     A distinct property value count
//
// Parameters:
//   propertyName:
public static CountProjection CountDistinct(string propertyName);

更新 2

根据 Firo 回答中的链接,我想出了这个替代方案。我将query 修改为分离的QueryOver 对象。接下来,我尝试了这个:

var rowcount = Session.QueryOver<InkoopFactuurListItem>()
    .Select(
        Projections.Alias(
            Projections.Count(Projections.SubQuery(detachedQuery)), "count"
        )
    )
    .FutureValue<int>();

但是,这会导致ArgumentOutOfRangeException

Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

【问题讨论】:

  • 当我向右滚动到火星轨道附近的某个地方时,我看到了 GROUP BY。那不是你想要的吗?
  • 如果您仔细观察,您看到的不是 1 个而是 2 个查询。一个有一组,一个没有。他们都应该有一个 group by。
  • 好的!很容易被忽视。第一个查询仅对子查询中的条件进行一次计数,以获得TOP 子句的标量值。它不应该分组。
  • 格特,这正是我的问题。为什么不分组?!分组是通过选择列表在主查询中进行的,所以它不应该在 rowcount-query 中吗?
  • 我想,这就是原因:nhibernate.jira.com/browse/NH-2411。 @RichardBrown 回答同样的问题“抱歉花了这么长时间才回到这个问题。不幸的是,我认为这个查询不能用 ICriteria 编写,这最终意味着它也不能在 QueryOver 中完成。”

标签: nhibernate telerik-mvc queryover future rowcount


【解决方案1】:

已编辑:

ToRowCountQuery 删除所有投影,甚至是分组。如果您自己运行查询,您将看到count(*) 在带有group by 的查询中将返回每个组的计数而不是组的数量。您必须 COUNT DISTINCT all group-columns 才能获得组数。

你需要像SELECT count(*) FROM (query) 这样的东西,这是不可能的。 我只能想到一个脆弱的解决方案,您可以在其中生成 sql,如 here 所示,然后

string sql = GenerateSQL(query.UnderlyingCriteria);
rowcount = session.CreateSQLQuery(string.Format("SELECT Count(*) FROM ({0})", sql)).SetParameter("???", KlantId).FutureValue<int>();

【讨论】:

  • Firo,这看起来像我需要的,但是我如何一次将分页查询和行计数查询发送到数据库?这就是 ToRowCount 和使用 Futures 背后的全部想法。
  • 请注意,由于 Min 和 Max 函数,我不能只指望单个字段。根据您的建议,我不知道该怎么做。
  • Firo,CountDistinct 不接受 IProjection 作为参数。
  • 啊,对不起,这是另一个类似的问题stackoverflow.com/questions/7832800/…
  • 我接受这个作为答案,因为它回答了我最初的问题,即 ToRowCountQuery 中的分组发生了什么。我将创建一个关于计算具有复杂分组的子查询中的行的新问题,因为在 SO 上尚未提出和回答。
猜你喜欢
  • 2014-01-12
  • 2021-10-28
  • 2016-09-30
  • 2016-03-16
  • 2014-02-03
  • 2012-03-11
  • 2013-09-07
  • 2016-08-12
  • 1970-01-01
相关资源
最近更新 更多