实体框架核心;在查询(MS)SQL Server

时间:2018-03-01 19:16:17

标签: c# sql-server entity-framework sql-order-by entity-framework-core

我尝试将以下查询与针对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中使用它,并且我希望对记录进行排序(按字母顺序排列)以使分页更加可用。 执行上述语句时出现以下错误:

  

ORDER BY子句在视图,内联函数中派生无效   表,子查询和公用表表达式,除非TOP,OFFSET   或者也指定了FOR XML。无效的NEXT选项用法   FETCH语句。 ORDER BY子句在视图中是无效的,内联   函数,派生表,子查询和公用表表达式,   除非还指定了TOP,OFFSET或FOR XML。无效的用法   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   完全。

此外,我对#34; view"这个词感到困惑。对我来说,术语视图是指使用CREATE VIEW ..语法创建的视图。是一个普通的,正常的' SQL查询还考虑了一个视图?或者EF Core是否在某种视图中包装请求,这是导致此错误的真正问题?

我不确定,但到目前为止所有的解决方案都是'我发现它看起来有点像hacky'。 想法?

1 个答案:

答案 0 :(得分:4)

让我们稍微简化一下。以下是我的测试结果。我还添加了https://www.python.org/dev/peps/pep-0008/#prescriptive-naming-conventions

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子句。