简体   繁体   English

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

[英]Entity Framework Core; using ORDER BY in query against a (MS) SQL Server

I'm trying to use the following query in combination with Entity Framework Core against a Microsoft SQL Server 2016: 我正在尝试对Microsoft SQL Server 2016将以下查询与Entity Framework Core结合使用:

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

I use this query like so: 我这样使用此查询:

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

I use this in a .NET Core REST API with pagination and I'd like to have the records sorted (alphabetically) to make the pagination more usable. 我在带有分页功能的.NET Core REST API中使用了此功能,并且希望对记录进行排序(按字母顺序),以使分页功能更加有用。 I get the following error when executing the above statement: 执行以上语句时出现以下错误:

The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.Invalid usage of the option NEXT in the FETCH statement. 除非还指定了TOP,OFFSET或FOR XML,否则ORDER BY子句在视图,内联函数,派生表,子查询和公共表表达式中无效.FETCH语句中选项NEXT的无效用法。 The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.Invalid usage of the option NEXT in the FETCH statement. 除非还指定了TOP,OFFSET或FOR XML,否则ORDER BY子句在视图,内联函数,派生表,子查询和公共表表达式中无效.FETCH语句中选项NEXT的无效用法。

Looking for similar issues I found these some other posts ( 1 , 2 , 3 ) but none of which where used in combination with EF Core and/or they were using it in a different context which does not apply in my case (eg subquery). 寻找类似的问题,我发现这些一些其他职位( 123 ),但其中没有一个与EF核心的组合,其中使用和/或它们在不同的环境中使用它不以我的情况下(例如,子查询)申请。

I tried to use the .OrderBy(..) syntax of EF instead of in the ORDER BY in the query but this doesn't solve the problem. 我试图在查询中使用EF的.OrderBy(..)语法,而不是在ORDER BY中使用,但这不能解决问题。 I also tried adding TOP 100 PERCENT after the SELECT in the query in combination with the ORDRE BY ; 我还尝试将查询中的SELECT之后的TOP 100 PERCENTORDRE BY结合使用; this worked but didn't order the column. 这行得通,但没有订购该专栏。 It just got ignored. 它只是被忽略了。 This limitation is described under the EF Limitations . 此限制在EF限制下进行描述。 I also found this post that replace the TOP 100 PERCENT... with TOP 99.99 PERCENT... or TOP 9999999... `. 我还发现此帖子TOP 99.99 PERCENT...TOP 9999999...代替TOP 100 PERCENT... This seems like it should work but it doesn't 'feel' right. 这似乎应该起作用,但是并不“感觉”正确。 This issue in general is further explained here . 一般而言,此问题将在此处进一步说明。

Summary: It is not advisable to use ORDER BY in Views. 摘要:建议不要在View中使用ORDER BY。 Use ORDER BY outside the views. 在视图外使用ORDER BY。 In fact, the correct design will imply the same. 实际上,正确的设计意味着相同。 If you use TOP along with Views, there is a good chance that View will not return all the rows of the table or will ignore ORDER BY completely. 如果将TOP与Views一起使用,则很有可能View不会返回表的所有行或将完全忽略ORDER BY。

Further I'm confused by the word "view". 此外,我对“视图”一词感到困惑。 For me, the term views refers to the usage of the ones created by the CREATE VIEW .. syntax. 对我而言,术语“视图”是指使用CREATE VIEW ..语法CREATE VIEW .. Is a plain, 'normal' SQL query also considered a view? 普通的“正常” SQL查询是否也被视为视图? Or is EF Core wrapping the request in some sort of view and this is the real issue causing this error? 还是EF Core将请求包装在某种视图中,这才是导致此错误的真正问题?

I'm not sure, but so far all the 'solutions' I found seem kind of 'hacky'. 我不确定,但是到目前为止,我发现的所有“解决方案”似乎都有些“ hacky”。 Thoughts? 思考?

Let's simplify things a bit. 让我们简化一下。 Here's what I came up for testing. 这就是我要进行测试的内容。 I've also added some code for printing the generated sql from EF queries . 我还添加了一些代码,用于打印从EF查询生成的sql

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}";
}

When we look at the value of generated we see what the sql of the query is: 当我们查看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]

Notice that there three order by clauses, the inner-most one is the one from rawSql . 请注意,存在三个order by子句,最里面的一个是rawSql的一个。

We can look at the error message to see why it's not legal: 我们可以查看错误消息以了解为什么它不合法:

The ORDER BY clause is invalid in [...] subqueries [...] unless OFFSET [...] is also specified. 除非也指定了偏移[...],否则ORDER BY子句在子查询[...]中无效。

The middle order by does include offset, so that's valid even though it's inside a subquery. 中间顺序by 确实包含偏移量,因此即使它在子查询中也有效。

To fix this, just simply remove the ordering from your rawSql and keep using the OrderBy() linq method. 要解决此问题,只需从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);

This generates: 这将产生:

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]

Now, all order by clauses are either not in subqueries, or have an offset clause. 现在,所有order by子句都不在子查询中,或者没有offset子句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM