实体框架:跳过/获取功能

YOh*_*han 5 c# entity-framework

我只是好奇Skip和Take函数如何在Entity Framework中工作(使用EF 6.1).

如果我做:

db.Events.OrderByDescending(x => x.Date).Take(maxPageSize).ToList();
Run Code Online (Sandbox Code Playgroud)

我得到一些清单(注意到一个事件已经完全消失).

如果我做:

db.Events.OrderByDescending(x => x.Date).Skip(0).Take(maxPageSize).ToList();
Run Code Online (Sandbox Code Playgroud)

我得到另一个列表,并且此处存在先前查询中的已事件.

任何人都知道我为什么要采取Skip() ZERO实体以便Take()采取我应该采取的措施?它几乎没有任何意义(至少对我而言)......

PS我无法使用SQL Server Profiler来检查生成的查询.

Bra*_*ley 3

尽管细节可能有所不同,但所接受的答案在描述发出的查询有何不同方面基本上是正确的。我经常看到实体框架发出的查询为“TOP (@maxPageSize) .... WHERE [ROW_NUMBER] > @skip”,这可能是相同的差异,但我不能 100% 确定它是否生成相同的查询执行计划。

需要明确注意的重要区别是,当“ORDER BY”不包含唯一的列名称时,这可能会产生不同的结果。

在我编写的代码中,当 @skip 值为 0 时,我们省略了“Skip”。我们有一个条目显示为最终条目。如果您随后转到应用了 @skip 值的下一页,则相同的条目将显示为该页面上的第一项。应该位于至少其中一个位置的“捆绑”项目从未出现。以下是每个发出的 SQL:

不跳过(在第 1 页生成):

SELECT TOP ({take number}) [Extent1].[Table1ID] AS [Table1ID], {snip a lot of other columns}
        FROM  [dbo].[Table1] AS [Extent1]
        LEFT OUTER JOIN [dbo].[Table2] AS [Extent2] ON [Extent1].[Table2ID] = [Extent2].[Table2ID]
        WHERE ({my where clause conditions})
        ORDER BY [Extent2].[MySortColumn] ASC
Run Code Online (Sandbox Code Playgroud)

跳过:

SELECT TOP ({take number}) [Filter1].[Table1ID], {snip a lot of other columns}
        FROM ( SELECT [Extent1].[Table1ID] AS [Table1ID], {snip a lot of other columns}, row_number() OVER (ORDER BY [Extent2].[MySortColumn] ASC) AS [row_number]
            FROM  [dbo].[Table1] AS [Extent1]
            LEFT OUTER JOIN [dbo].[Table2] AS [Extent2] ON [Extent1].[Table2ID] = [Extent2].[Table2ID]
            WHERE ({my where clause conditions})
        )  AS [Filter1]
        WHERE [Filter1].[row_number] > {skip number}
        ORDER BY [Filter1].[MySortColumn] ASC
Run Code Online (Sandbox Code Playgroud)

重要的一点是回到“SQL 101”并记住,如果没有“order by”,则无法保证顺序。这种发出的差异会导致一个项目在网格的多个页面上重复,而另一个项目根本不会显示,这让我发现这在实体框架中更为重要,其中生成的确切 SQL 并不直接由您控制,并且未来的 EF 版本可能会出乎意料地有所不同

目前,您可以通过始终包含 Skip(0) 来避免这种情况,它将发出第二个查询,但 {skip number} 只是为零。在我的测试中,这似乎总是使用 T-SQL 的默认规则为决胜局发出相同的顺序。我认为假设这一定会在实体框架的未来版本中起作用并不是最佳实践。相反,我建议您考虑探索自己的打破平局策略。就我而言,应该可以打破“Table1ID”的束缚,因为它代表唯一的身份主键列。不过,所附文章针对更复杂的情况提供了建议。