EF Core 3.1 生成 ORDER BY(SELECT 1),这会破坏旧代码



我正在将我们的项目从 .NET Core 2.1 升级到 3.1,并且遇到以下 EF Core 问题。

我有以下代码:

var all = this.Context.Devices.OrderBy(c => c.Id).Where(predicate).Distinct();
var result = await all.Skip(pagedRequest.Offset).Take(pagedRequest.Limit).ToListAsync();
var totalCount = await all.CountAsync();

这基本上用于分页,并将总元素计数提供给客户端。谓词是动态生成的筛选条件。为什么 Distinct(( 真的被使用我还没有弄清楚(这是我面临的一些旧代码(。人们可能会争论是否需要它,但这肯定是有效的,因此不会改变问题。 但是,将生成以下 SQL:

SELECT [d].[Id], ...
FROM [Device] AS [d]
WHERE ([d].[State] = 2) AND EXISTS (
SELECT 1
FROM [AnotherTable] AS [r]
WHERE ([d].[Id] = [r].[DeviceId]) AND ([r].[UserId] = 1))
ORDER BY (SELECT 1)
OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY

比我得到ORDER BY items must appear in the select list if SELECT DISTINCT is specified.它没有出现在 .net ef 2.1 中。我查看了重大更改,没有找到任何可以解释它的东西。我也不明白到底是什么ORDER BY (SELECT 1),为什么它是按 id 生成的而不是按 id 排序。

我现在检查了使用相同的代码生成的 SQL,但 EF 2.1。正如我所期望的那样,只有ORDER BY [c].[Id]而不是ORDER BY (SELECT 1),这完全一样。

有人可以解释这种行为吗?

PS:另一个有趣的事情是,如果我将鼠标悬停在调试器中的all上并查看"结果"视图,则会看到对象。异常来自添加了 Skip 和 Take 的第二个代码行。

OrderBy后跟Distinct表示all没有定义的排序(Distinct可以并且将会重新排序(。

反过来,这意味着SkipTake定义不明确,因为它们针对一组无序行进行操作。

所以代码总是被破坏,只是现在更加明显。

如果确保SkipTake针对唯一定义所有行的顺序的IOrderedEnumerable,更具体地说,唯一定义所有行的顺序,则代码将得到明确定义,并且该特定排序将反映在 EF 生成的代码中。

一种方法是 删除Distinct.另一个是在Distinct之后再次致电OrderBy


我不明白到底是什么ORDER BY (SELECT 1)

这是一个不幸的解决方法,有人发现可以使用FETCH NEXT时未指定ORDER BY时生成的警告静音。不幸的是,人们可以并且会做这样的事情(即使是在 EF 等工具上工作的人(,而不是考虑警告的存在是有充分理由的(行集是无序的(。

最新更新