我正在尝试将以下查询与实体框架核心结合使用,以针对Microsoft SQL Server 2016:
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 在 获取语句。ORDER BY 子句在视图中无效,内联 函数、派生表、子查询和公用表表达式, 除非还指定了 TOP、OFFSET 或 FOR XML。无效的用法 选项 FETCH 语句中的下一步。
寻找类似的问题,我发现了这些其他一些帖子(1、2、3),但没有一个与 EF Core 结合使用和/或他们在不适用于我的情况的不同上下文中使用它(例如子查询)。
我尝试在查询中使用 EF 的.OrderBy(..)
语法而不是在ORDER BY
中,但这并不能解决问题。我还尝试在查询中的SELECT
后添加TOP 100 PERCENT
与ORDRE BY
;这有效,但没有对列进行排序。它只是被忽略了。EF 限制中介绍了此限制。我还发现了这篇文章,它将TOP 100 PERCENT...
替换为TOP 99.99 PERCENT...
或TOP 9999999...
'。这似乎应该有效,但它"感觉"不对。 这里将进一步解释这个问题。
摘要:不建议在视图中使用 ORDER BY。使用排序方式 视野之外。事实上,正确的设计将意味着相同的内容。如果 您将 TOP 与视图一起使用,视图很有可能会 不返回表的所有行,或者将忽略 ORDER BY 完全。
此外,我对"视图"这个词感到困惑。对我来说,术语视图是指由CREATE VIEW ..
语法创建的视图的用法。普通的"普通"SQL 查询是否也被视为视图?或者 EF Core 是否将请求包装在某种视图中,这是导致此错误的真正问题?
我不确定,但到目前为止,我发现的所有"解决方案"似乎都有点"黑客"。 思潮?
让我们简化一下。这是我提出要测试的内容。我还添加了一些代码,用于打印从 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}";
}
当我们查看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 [...]。
中间顺序 by确实包含偏移量,因此即使它在子查询内也是有效的。
若要解决此问题,只需从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]
现在,所有排序依据子句要么不在子查询中,要么具有偏移量子句。