实体框架核心;在查询(MS)SQL Server时使用ORDER BY

问题描述 投票:1回答:1

我正在尝试将以下查询与针对Microsoft SQL Server 2016的Entity Framework Core结合使用:

SELECT [a], [b], [c]
FROM [x]
WHERE [a] = {0}
ORDER BY  [b]

我这样使用这个查询:

context.MySet.AsNoTracking()
  .FromSql(MyQuery, aValue)
  .Skip(pageSize * page)
  .Take(pageSize)
  .Select(x => x.ToJsonDictionary())
  .ToList()

我在带有分页的.NET Core REST API中使用它,我希望对记录进行排序(按字母顺序排列)以使分页更有用。执行上述语句时出现以下错误:

除非还指定了TOP,OFFSET或FOR XML,否则ORDER BY子句在视图,内联函数,派生表,子查询和公用表表达式中无效。在FETCH语句中,NEXT选项的使用无效。除非还指定了TOP,OFFSET或FOR XML,否则ORDER BY子句在视图,内联函数,派生表,子查询和公用表表达式中无效。在FETCH语句中,NEXT选项的使用无效。

寻找类似的问题我发现了一些其他帖子(123),但没有一个与EF Core结合使用和/或他们在不同的情况下使用它在我的情况下不适用(例如子查询) 。

我尝试使用EF的.OrderBy(..)语法而不是查询中的ORDER BY,但这并没有解决问题。我还尝试在TOP 100 PERCENT中加入SELECT并与ORDRE BY结合使用;这工作但没有订购专栏。它被忽略了。这个限制在EF Limitations下描述。我还发现this postTOP 100 PERCENT...TOP 99.99 PERCENT...替换TOP 9999999...。这似乎应该有效,但它“感觉”不对。 here进一步解释了这个问题。

简介:不建议在视图中使用ORDER BY。在视图外使用ORDER BY。事实上,正确的设计意味着相同。如果您将TOP与Views一起使用,View很可能不会返回表的所有行或完全忽略ORDER BY。

此外,我对“视图”一词感到困惑。对我来说,术语视图是指使用CREATE VIEW ..语法创建的视图。一个简单的,“正常”的SQL查询也被认为是一个视图?或者EF Core在某种视图中包装请求,这是导致此错误的真正问题?

我不确定,但到目前为止,我发现的所有“解决方案”似乎都是“hacky”。思考?

c# sql-server entity-framework sql-order-by entity-framework-core
1个回答
3
投票

让我们简化一下。这是我提出的测试方法。我还添加了some code for printing the generated sql from EF queries

class Program
{
    static void Main(string[] args)
    {
        DbClient context = new DbClient();

        var rawSql = "select [Id], [Title] from Post order by [Title]";

        var query = context.Posts.AsNoTracking()
            .FromSql(rawSql)
            .Skip(1)
            .Take(4)
            .OrderBy(x => x.Title);

        var generated = query.ToSql();

        var results = query.ToList();
    }
}

class DbClient : DbContext
{
    public DbSet<Post> Posts { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("conn_string");
    }
}

class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public override string ToString() => $"{Id} | {Title}";
}

当我们查看generated的值时,我们会看到query的sql是什么:

SELECT [t].[Id], [t].[Title]
FROM (
    SELECT [p].[Id], [p].[Title]
    FROM (
        select [Id], [Title] from Post order by [Title]
    ) AS [p]
    ORDER BY (SELECT 1)
    OFFSET 1 ROWS FETCH NEXT 4 ROWS ONLY
) AS [t]
ORDER BY [t].[Title]

请注意,有三个order by条款,最内层的一个是来自rawSql的条款。

我们可以查看错误消息,看看为什么它不合法:

[...]子查询中的ORDER BY子句无效[...],除非还指定了OFFSET [...]。

中间顺序包含偏移量,因此即使它在子查询中也是有效的。

要解决这个问题,只需从rawSql中删除顺序并继续使用OrderBy() linq方法。

var rawSql = "select [Id], [Title] from Post";

var query = context.Posts.AsNoTracking()
    .FromSql(rawSql)
    .Skip(1)
    .Take(4)
    .OrderBy(x => x.Title);

这会产生:

SELECT [t].[Id], [t].[Title]
FROM (
    SELECT [p].[Id], [p].[Title]
    FROM (
        select [Id], [Title] from Post
    ) AS [p]
    ORDER BY (SELECT 1)
    OFFSET 1 ROWS FETCH NEXT 4 ROWS ONLY
) AS [t]
ORDER BY [t].[Title]

现在,所有order by子句都不在子查询中,或者具有offset子句。

© www.soinside.com 2019 - 2024. All rights reserved.