在以下 linq 语句(在 .net 4.5 中)中,我尝试对两个表执行左联接,然后根据第二个表上完成的排序仅获取每个联接的第一行。
using (var context = new TestEntities())
{
var items = ctx.FirstTables
.GroupJoin(
ctx.SecondTables,
first => first.IntJoin,
second => second.IntJoin,
(firstTableRow, secondTableRows)
=> new { firstTableRow, secondTableRows })
.Select(
result => new
{
result.firstTableRow.IntJoin,
NewWanted = result.secondTableRows
.OrderByDescending(x => x.Sort)
.Select(x => (int?)x.Wanted)
.DefaultIfEmpty(null)
.FirstOrDefault()
});
}
但是,OrderByDescending
调用并未应用于第二个表,因此 Wanted
列始终返回数据库中第一列的值。
因此给出下表值
第一个表:
IntJoin
0
1
2
null
第二个表:
IntJoin || Sort || Wanted
0 0 1
0 1 2
0 2 3
1 0 6
1 1 5
1 2 4
null 0 7
null 1 9
null 2 8
我希望得到以下列表:
IntJoin || NewWanted
0 3
1 4
2 null
null 8
我得到的是这个
IntJoin || NewWanted
0 1
1 6
2 null
null 7
并在 .net Core 2.0.1 中运行的 EntityFrameworkCore 中获取以下内容
IntJoin || NewWanted
0 3
1 4
2 null
null null
因此,.net Framework 中的 Entity Framework 忽略了 OrderByDescending
调用,而 Entity Framework Core 则不然(.net Core 似乎无法处理 null 比较。我没有使用 core并且仅创建了一个示例来测试差异,因此该问题最好留给(或可能在)另一个问题中回答)
我已经在 .net 4.5 和 4.7(使用 Entity Framework 6.2.0)、.net Core 2.0(使用 Entity Framework Core 2.0.1)以及 Microsoft Sql Server 2008 和 2016 中尝试了所有这些,并取得了相同的结果。
我知道我可能可以在 GroupJoin
和 Select
之间调用 .ToList()
但这是更大查询和执行的一部分内存中的查询将非常令人望而却步。
我还尝试过调用 OrderBy
以及不同的值,包括 Select
中的 Sort
列,没有任何区别
最佳答案
看起来您遇到了(与 EF Core 相比的少数几个)EF6 查询转换错误,因为生成的 SQL 查询没有 ORDER BY
子句:
SELECT
1 AS [C1],
[Project3].[IntJoin] AS [IntJoin],
[Project3].[C1] AS [C2]
FROM ( SELECT
[Extent1].[IntJoin] AS [IntJoin],
(SELECT TOP (1)
[Project1].[Wanted] AS [Wanted]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN (SELECT
[Extent2].[Wanted] AS [Wanted]
FROM [dbo].[SecondTable] AS [Extent2]
WHERE ([Extent1].[IntJoin] = [Extent2].[IntJoin]) OR (([Extent1].[IntJoin] IS NULL) AND ([Extent2].[IntJoin] IS NULL)) ) AS [Project1] ON 1 = 1) AS [C1]
FROM [dbo].[FirstTable] AS [Extent1]
) AS [Project3]
解决方案是将 DefaultIfEmpty
移到 OrderByDescending
之前(基本上遵循“常规”LINQ 左外连接模式:
NewWanted = result.secondTableRows
.DefaultIfEmpty() // <--
.OrderByDescending(x => x.Sort)
.Select(x => (int?)x.Wanted)
//.DefaultIfEmpty()
.FirstOrDefault()
翻译为:
SELECT
1 AS [C1],
[Extent1].[IntJoin] AS [IntJoin],
[Limit1].[Wanted] AS [Wanted]
FROM [dbo].[FirstTable] AS [Extent1]
OUTER APPLY (SELECT TOP (1) [Project2].[Wanted] AS [Wanted]
FROM ( SELECT
[Project1].[Sort] AS [Sort],
[Project1].[Wanted] AS [Wanted]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN (SELECT
[Extent2].[Sort] AS [Sort],
[Extent2].[Wanted] AS [Wanted]
FROM [dbo].[SecondTable] AS [Extent2]
WHERE ([Extent1].[IntJoin] = [Extent2].[IntJoin]) OR (([Extent1].[IntJoin] IS NULL) AND ([Extent2].[IntJoin] IS NULL)) ) AS [Project1] ON 1 = 1
) AS [Project2]
ORDER BY [Project2].[Sort] DESC ) AS [Limit1]
并产生所需的结果。
关于c# - 子查询,在 Select 内部,不将 Order By 应用于基础查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47779811/