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

时间:2014-05-23 06:57:09

标签: c# entity-framework

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

如果我这样做:

db.Events.OrderByDescending(x => x.Date).Take(maxPageSize).ToList();

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

如果我这样做:

db.Events.OrderByDescending(x => x.Date).Skip(0).Take(maxPageSize).ToList();

我得到另一个列表,之前的查询中出现的事件就在这里。

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

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

2 个答案:

答案 0 :(得分:2)

生成了完全不同的查询。在第一种情况下,您只需前N行:

SELECT TOP(@maxPageSize) ...
FROM [Events]
ORDER BY [Date] DESC

在第二种情况下,行号用于过滤有序行:

SELECT ...
FROM (SELECT ROW_NUMBER() OVER (ORDER BY [Date] DESC) AS [ROW_NUMBER], ...
      FROM [Events])
WHERE [ROW_NUMBER] BETWEEN @skip + 1 AND @skip + @maxPageSize
ORDER BY [ROW_NUMBER]

ROW_NUMBER()返回从1开始的行号。如果页面大小为5,则第一个查询将按预期返回前5行。第二个查询将返回数字为1,2,3,4,5的行。因此,当@skip参数等于零时,这两个查询之间应该没有任何区别。

确保您确实执行具有完全相同参数的精确指定的查询。运行这些查询时,确保事件表具有完全相同的数据。检查您是否使用最新版本的组件。

答案 1 :(得分:2)

尽管细节可能有所不同,但在描述发出的查询有何不同时,公认的答案最正确。我通常看到实体框架以“ TOP(@maxPageSize).... WHERE [ROW_NUMBER]> @skip”的形式发出查询,这可能是相同的区别,但是我不确定它会生成相同的查询执行吗?计划。

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

在我编写的代码中,当@skip值为0时,我们省略了“跳过”。最后一个条目出现了一个条目。如果然后转到应用了@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

跳过:

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

重要的收获是,一路回到“ SQL 101”并记住without "order by", order is not guaranteed。这种发光方式的差异导致一个项目在网格的多个页面上重复出现,而另一个项目却从未出现过,这使我看到,这在实体框架中更为重要,因为在实体框架中生成的确切SQL并不直接在您的控件中显示, 在将来的EF版本中可能会意外地有所不同

当前,您可以通过始终包含Skip(0)来避免此情况,后者将发出第二个查询,但{skip number}只是零。在我的测试中,这似乎总是使用T-SQL的默认规则为平局决胜局发出相同的顺序。我认为,并不是最好的做法是假设这在将来的Entity Framework这样的版本中一定会起作用。我建议您考虑自己探索tie-breaking strategy。就我而言,应该有可能打破“ Table1ID”上的关系,因为它代表唯一的身份主键列。附件中提供了针对更复杂情况的建议。