c# - 子查询,在 Select 内部,不将 Order By 应用于基础查询

标签 c# entity-framework linq-to-sql

在以下 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 中尝试了所有这些,并取得了相同的结果。

我知道我可能可以在 GroupJoinSelect 之间调用 .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/

相关文章:

.net - .NET 中的 n 层 CRUD 应用程序的方法

c# - Entity Framework - 使其只读?

c# - 如何使用 LINQ 在函数中定义返回类型?

.net - Linq to SQL 有什么问题?

c# - 理解这个 Lambda 表达式

C#线程和轮询

c# - 如何同时构建字符串?

c# - 在 switch 语句案例中使用属性?

c# - MVC Entity Framework 将一列作为数组

c# - ASP.NET - LinqDataSource 中的高级 Where 子句