在下面的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
列始终返回数据库中第一列的值。
因此给出了下表值
FirstTable:
IntJoin
0
1
2
null
SecondTable:
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中的实体框架忽略了OrderByDescending
调用而实体框架核心不是(.net Core似乎无法处理null比较。我没有使用核心而只是创建一个测试差异的例子,这个问题最好留给(或可能在另一个问题中回答)
我已经在.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中尝试了所有这些并获得了相同的结果。
我知道我可能会在.ToList()
和GroupJoin
之间调用Select
,但这是较大查询的一部分,在内存中执行查询会非常令人望而却步。
我也尝试调用OrderBy
以及不同的值,包括Sort
中的Select
列没有任何差异
答案 0 :(得分:2)
由于生成的SQL查询没有ORDER BY
子句,因此看起来你已经击中(少数几个与EF Core相比)EF6查询转换错误:
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]
并产生所需的结果。