2010-10-06 59 views
39

只是好奇如何跳过&采取应该工作。我得到了我希望在客户端看到的结果,但是当我连接AnjLab SQL事件探查器并查看正在执行的SQL时,它看起来好像是查询整行行并将其返回给客户。实体框架/ Linq to SQL:跳过并采取

它真的返回所有的行,然后用客户端上的LINQ排序和缩小的东西?

我试着用Entity Framework和Linq来做到这一点;两者似乎都有相同的行为。

不知道这有什么差别,但我使用C#在2010年VWD

任何见解?

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(注:我不包括统计查询):

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 

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

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

问题解决了

必须包装在表达传入的lambda函数:

Expression<Func<Store,string>> sort 
+0

你可以给我们的那种FUNC代码? – 2010-10-06 15:15:34

+0

当然,我只是传递一个lambda。例如:x => x.Name,x => x.LegalName,x => x.YearEstablished.ToString() – Sam 2010-10-06 15:28:54

+0

开始认为我应该传递一个字符串,然后使用switch语句为LINQ设置适当的orderby参数查询:(第一个方法非常酷,涉及的代码少得多,我不明白为什么它不能正常工作。不知道到底发生了什么,似乎.OrderBy和.OrderByDescending触发数据库提取,然后应用排序,然后跳过并采取。也许这是它虽然...也许OrderBy不知道如何将x => x.Name转换为适当的SQL,因此它提取结果集,然后应用排序和筛选。 – Sam 2010-10-06 15:46:16

回答

29

下工作,并完成我一直在寻找简单:

Expression<Func<Store, string>> sort 
+0

我有类似的问题。我在SQL Profiler中发现,查询只是SELECT * FROM的,并将其追溯到事实上,这个Expression <>参数可能在调用中缺失。我更新了它(我使用EF4.1作为参考)并解决了我的问题。 – Amadiere 2011-07-19 14:02:24

+0

任何人都知道这是为什么?我有完全相同的问题。我以为我把整个表达式保存为一个IQueryable,而不用调用ToList或枚举表达式的其他东西。 Func是否会在枚举表达式时导致枚举? – 2014-01-28 17:52:42

+0

@BrianSweeney我相信这样做的原因是,如果排序查询不包含在表达式中,那么linq无法为它构建表达式树,以便将其转换为sql。因此,它必须枚举查询以在执行跳转/取前进行排序 – Anduril 2014-07-30 11:30:59

6

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

采取

只有Take(10).ToList()做,做了SELECT TOP 10 * FROM

跳过

跳过的工作方式有些不同,因为在TSQL没有“限价”的功能。但是,它会创建基于此ScottGu blog post中所述工作的SQL查询。

如果你看到整个记录集返回,这可能是因为你在某个地方做的ToList()太早。

+0

例如:db.Stores.OrderBy(x => x.Name).Skip(5).Take(5).ToList() – Sam 2010-10-06 12:45:15

+0

是的,但更早。是一些其他方法做一个ToList()on your original set。 – 2010-10-06 13:39:14

+0

上面的代码... – Sam 2010-10-06 13:56:49

0

试试这个:

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()。

+0

结果是一个ObjectSet 类型。结果.OrderByDescending(排序)返回IOrderedEnumerable ,因此它不能分配给结果。你给了我一些想法尝试一下。一旦我测试过,会回复。 – Sam 2010-10-06 14:37:52

+0

这就是他们都回来的。直到您指定.Select()或.ToList()。 – 2010-10-06 14:44:46

+0

正确,但编译器阻止“if(desc)results = results.OrderByDescending(sort)”,因为类型不同。我还发现,当我使用.Skip时没有调用.OrderBy(遇到!desc时),我得到一个错误。发布编辑到我原来​​的帖子与其他调查结果。 – Sam 2010-10-06 14:55:39

3

实体框架6解决方法:

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; 
} 

是固定的,对我来说是改变Func键排序参数,主要的事情这里...

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

Ë 。G。

using System.Data.Entity; 
.... 

int skip = 5; 
int take = 10; 

myQuery.Skip(() => skip).Take(() => take); 
+1

我想你误解了这个问题。 OP从未提及参数化Skip和Take,只是它们没有在SQL中执行(由于在OrderBy中错误地使用了'Func <,>'而不是'Expression >')。这可能就是为什么你把我的问题标记为重复,即使它们不一样。 – GWB 2015-10-30 14:16:19

0

我创建了简单的扩展:

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(); 
}