Entity Framework / Linq to SQL:Skip&Take

只是好奇Skip&Take应该如何工作。 我得到了我希望在客户端看到的结果,但是当我连接AnjLab SQL事件探查器并查看正在执行的SQL时,它看起来好像正在查询并将整个行集返回给客户。

它真的返回所有的行,然后在客户端用LINQsorting和缩小的东西?

我试过用Entity Framework和Linq to SQL来做这件事。 两者似乎都有相同的行为。

不知道它有什么不同,但我在VWD 2010中使用C#。

任何见解?

public IEnumerable<Store> ListStores(Func<Store, string> sort, bool desc, int page, int pageSize, out int totalRecords) { var context = new TectonicEntities(); totalRecords = context.Stores.Count(); int skipRows = (page - 1) * pageSize; if (desc) return context.Stores.OrderByDescending(sort).Skip(skipRows).Take(pageSize).ToList(); return context.Stores.OrderBy(sort).Skip(skipRows).Take(pageSize).ToList(); } 

生成的SQL(注意:我不包括Count查询):

 SELECT [Extent1].[ID] AS [ID], [Extent1].[Name] AS [Name], [Extent1].[LegalName] AS [LegalName], [Extent1].[YearEstablished] AS [YearEstablished], [Extent1].[DiskPath] AS [DiskPath], [Extent1].[URL] AS [URL], [Extent1].[SecureURL] AS [SecureURL], [Extent1].[UseSSL] AS [UseSSL] FROM [dbo].[tec_Stores] AS [Extent1] 

经过一番进一步的研究,我发现以下的方式是我期望的方式:

 public IEnumerable<Store> ListStores(Func<Store, string> sort, bool desc, int page, int pageSize, out int totalRecords) { var context = new TectonicEntities(); totalRecords = context.Stores.Count(); int skipRows = (page - 1) * pageSize; var qry = from s in context.Stores orderby s.Name ascending select s; return qry.Skip(skipRows).Take(pageSize); } 

生成的SQL:

 SELECT TOP (3) [Extent1].[ID] AS [ID], [Extent1].[Name] AS [Name], [Extent1].[LegalName] AS [LegalName], [Extent1].[YearEstablished] AS [YearEstablished], [Extent1].[DiskPath] AS [DiskPath], [Extent1].[URL] AS [URL], [Extent1].[SecureURL] AS [SecureURL], [Extent1].[UseSSL] AS [UseSSL] FROM ( SELECT [Extent1].[ID] AS [ID], [Extent1].[Name] AS [Name], [Extent1].[LegalName] AS [LegalName], [Extent1].[YearEstablished] AS [YearEstablished], [Extent1].[DiskPath] AS [DiskPath], [Extent1].[URL] AS [URL], [Extent1].[SecureURL] AS [SecureURL], [Extent1].[UseSSL] AS [UseSSL], row_number() OVER (ORDER BY [Extent1].[Name] ASC) AS [row_number] FROM [dbo].[tec_Stores] AS [Extent1] ) AS [Extent1] WHERE [Extent1].[row_number] > 3 ORDER BY [Extent1].[Name] ASC 

我真的很喜欢第一种select的方式。 传入一个lambdaexpression式进行sorting。 有什么办法在LINQ to SQL orderby语法中完成同样的事情吗? 我尝试使用qry.OrderBy(sorting).Skip(skipRows).Take(pageSize),但最终给了我与我的第一个代码块相同的结果。 让我相信我的问题与OrderBy有某种联系。

====================================

问题解决了

不得不在expression式中包装传入的lambda函数:

 Expression<Func<Store,string>> sort 

以下工作和完成我正在寻找的简单性:

 public IEnumerable<Store> ListStores(Expression<Func<Store, string>> sort, bool desc, int page, int pageSize, out int totalRecords) { List<Store> stores = new List<Store>(); using (var context = new TectonicEntities()) { totalRecords = context.Stores.Count(); int skipRows = (page - 1) * pageSize; if (desc) stores = context.Stores.OrderByDescending(sort).Skip(skipRows).Take(pageSize).ToList(); else stores = context.Stores.OrderBy(sort).Skip(skipRows).Take(pageSize).ToList(); } return stores; } 

固定它的主要事情是改变Funcsorting参数为:

 Expression<Func<Store, string>> sort 

只要你不这样做queryable.ToList().Skip(5).Take(10) ,它不会返回整个logging集。

采取

只做Take(10).ToList() ,做一个SELECT TOP 10 * FROM

跳跃

跳过工作有点不同,因为TSQL中没有“LIMIT”函数。 但是,它会创build一个基于ScottGu博客文章中描述的工作的SQL查询。

如果你看到整个logging集被返回,那可能是因为你在某个地方做了一个ToList()

entity framework6解决scheme在这里…

http://anthonychu.ca/post/entity-framework-parameterize-skip-take-queries-sql/

例如

 using System.Data.Entity; .... int skip = 5; int take = 10; myQuery.Skip(() => skip).Take(() => take); 

尝试这个:

 public IEnumerable<Store> ListStores(Func<Store, string> sort, bool desc, int page, int pageSize, out int totalRecords) { var context = new TectonicEntities(); var results = context.Stores; totalRecords = results.Count(); int skipRows = (page - 1) * pageSize; if (desc) results = results.OrderByDescending(sort); return results.Skip(skipRows).Take(pageSize).ToList(); } 

事实上,最后.ToList()是不是真的有必要,因为你正在返回IEnumerable …

将会有2个数据库调用,一个用于计数,另一个用于执行ToList()。

我创build了简单的扩展:

 public static IEnumerable<T> SelectPage<T, T2>(this IEnumerable<T> list, Func<T, T2> sortFunc, bool isDescending, int index, int length) { List<T> result = null; if (isDescending) result = list.OrderByDescending(sortFunc).Skip(index).Take(length).ToList(); else result = list.OrderBy(sortFunc).Skip(index).Take(length).ToList(); return result; } 

简单使用:

 using (var context = new TransportContext()) { var drivers = (from x in context.Drivers where x.TransportId == trasnportId select x).SelectPage(x => x.Id, false, index, length).ToList(); }