【问题标题】:NHibernate ORDER BY CURRENT_TIMESTAMP conflicts with DISTINCTNHibernate ORDER BY CURRENT_TIMESTAMP 与 DISTINCT 冲突
【发布时间】:2021-11-18 21:56:29
【问题描述】:

谁能解释一下为什么MsSql2012Dialect 上的NHibernate 会生成服务器无法处理的查询?当没有明确指定排序时,它会以这种方式构建查询。

...
ORDER BY CURRENT_TIMESTAMP
OFFSET 0 ROWS FETCH FIRST 10 ROWS ONLY 

【问题讨论】:

  • 当需要PAGING 时,它使用OFFSET 子句。在这种情况下,它将按时间戳顺序选择前 10 行。你有某种分页,对吧?
  • 我找到了问题所在。我们的查询中有 SELECT DISTINCT 并且没有排序。因此,HNibernate 生成与 DISTINCT 冲突的默认 ORDER BY CURRENT_TIMESTAMP 。错误是 - 如果指定了 SELECT DISTINCT,则 ORDER BY 项目必须出现在选择列表中。
  • 归根结底,如果您使用分页但没有提供实际的排序条件,那么使用它的函数也可以称为“选择 10 个随机行”,因为查询如图所示不保证它将返回哪些行。

标签: sql-server nhibernate pagination


【解决方案1】:

这是jira 中注册的未解决错误,根据建议,这是我的解决方法:

public class MyMsSql2012Dialect : MsSql2012Dialect
{
    public override SqlString GetLimitString(SqlString querySqlString, SqlString offset, SqlString limit)
    {
        var result = base.GetLimitString(querySqlString, offset, limit);

        return result.Replace("ORDER BY CURRENT_TIMESTAMP", "ORDER BY 1");
    }
}

【讨论】:

  • 更好的解决方案是向 NHibernate 显式提供 ORDER BY 列,并将该列包含在 SELECT 列表中。
【解决方案2】:

正如您在问题中所说,如果没有明确指定 ORDER BY,则会生成以下查询:

 SELECT
    distinct this_.ColumnName as y0_ 
 FROM
    [DB].[dbo].Table this_ 
 ORDER BY
    CURRENT_TIMESTAMP OFFSET 0 ROWS FETCH FIRST 10 ROWS ONLY;

错误是:

如果指定了 SELECT DISTINCT,则 ORDER BY 项目必须出现在选择列表中。

仅当同时提供 Projections.DistinctTake(1) 且 SQL Server 版本高于 2012(DialectMsSql2012Dialect 或更高版本)时才会发生错误。

更好的解决方案是向 NHibernate 显式提供 ORDER BY 列,并将该列包含在 SELECT 列表中。

Session.QueryOver<Entity>()
    .Select(
            Projections.Distinct(Projections.Property<Entity>(x => x.ColumnName))
           )
    .Where(....)
    .OrderBy(Projections.Property<Entity>(x => x.ColumnName)).Asc()
    .Take(1);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    相关资源
    最近更新 更多