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

Max*_*ikh 1 .net sql sql-server entity-framework core

我正在将我们的项目从 .net core 2.1 升级到 3.1,并且我面临着以下 EF 问题。我有以下代码:

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();
Run Code Online (Sandbox Code Playgroud)

这基本上用于分页,并且还向客户端提供总元素数。Predicate 是动态生成的过滤条件。为什么 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Dam*_*ver 5

OrderBy其次是没有定义排序的Distinct手段(可以并且将重新排序事物)。allDistinct

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

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

如果您确定Skip并且Take正在针对一个IOrderedEnumerable,更具体地说,一个唯一定义所有行的排序的代码,那么代码将是明确定义的,并且特定的排序将反映在 EF 生成的代码中。

一种方法是删除Distinct. 另一个办法是另一个呼叫OrderBy Distinct


我不明白这是什么鬼 ORDER BY (SELECT 1)

这是一个不幸的变通方法,有人发现沉默警告无时生成ORDER BY使用时指定FETCH NEXT。不幸的是,人们可以并且将会做这样的事情(即使是使用像 EF 这样的工具的人),而不是考虑警告的存在是有充分理由的(行集是无序的)。