2017-08-25 63 views
0

我最近在尝试使用跳过并获取LINQ语句时遇到错误。跳过()和Take()作为可枚举对象作为可查询

我的发言看起来像这样。

DbConxtext.MyTable.Get(c => c.UserID == id) 
    .OrderBy(orderProperty).Skip(index).Take(length).ToList(); 

这给了我这个错误

附近有语法错误 '偏移'。\ r \ n无效的NEXT在FETCH语句

我发现了选项的使用,这是造成因为OFFSET NEXT和FETCH在sql server 2008上不起作用,但我知道我在代码的其他地方使用了分页,并且它们都工作正常。

奏效,这一次是跳过采取是可枚举的扩展上对didnt的那些工作,可查询的那些的那些之间的区别。

因此,添加AsEnumerable()查询修复了我的问题。这似乎生成SQL使用SELECT TOP(10)而不是OFFSETFETCH

编辑:在阅读了一遍之后,我意识到AsEnumerable不会生成不同的SQL。它将执行查询并执行内存中的跳转。

DbConxtext.MyTable.Get(c => c.UserID == id) 
    .OrderBy(orderProperty).AsEnumerable().Skip(index).Take(length).ToList(); 

我的问题是什么是使用跳过,并采取的可枚举扩展VS可查询的区别。

为什么EF决定在两种情况之间生成不同的SQL。

+0

'这似乎生成SQL使用SELECT TOP(10)'它不会做这样的事情。您应该查看生成的* actual * SQL以查看两个查询之间的差异。 – Servy

+0

区别在于'Skip'和'Take'将被应用于内存而不是DB中。基本上你会得到所有的结果,然后将其过滤到你想要的结果。 – juharr

+1

为什么你认为使用AsEnumerable时会生成一个select? AsEnumerable表示*在这里停止生成SQL *。我有兴趣了解为什么人们相信编程方面的错误;是什么导致你这种信念? –

回答

1

就是使用SkipTake作为Enumerable VS Queryable扩展之间的区别。

当调用上实现IQueryable类型SkipTake,所述Queryable扩展方法将被绑定,和底层LINQ提供(例如LINQ到实体)将处理Skip和/或Take和转它转化为基础数据提供者的命令(例如SQL语句)。提供者实际上是否支持或者正确处理它们直到运行时才会知道。

当你打电话给他们上实现IEnumerable(但不是IQueryable)一个类型,Enumerable扩展方法将被绑定,这只是处理由Queryable查询生成的内存中集合的命令。

为什么EF决定在两种情况之间生成不同的SQL。

在第二种情况下,生成的SQL查询仅合并直到注入AsEnumerable()之前的命令。这是EF提供商所看到的。从那时起,这些命令将被绑定到Enumerable扩展方法,并将处理剩余的内存命令。

这似乎产生了使用SELECT TOP(10)

我高度怀疑,SQL。 应该发生的是SQL查询将返回所有记录,但由Take生成的内存中迭代器将只返回前十个。

如果您希望对SQL 2008数据库正确处理SKIP和TAKE,请参阅this question了解其他解决方案。

+0

注意.AsEnumerable()。Skip()。对于Skip()和SQL Server的小值,Take()相对有效。客户端只需读取()并忽略几行。 –

+0

@ DavidBrowne-Microsoft对于Skip而不是Take是真的。 – Servy

+0

@ DavidBrowne-Microsoft但是整个集合将被读入内存,对吗?所以,如果你从1M行中取出10个,它在内存中的效率会低得多,不是吗? –