2017-08-25 29 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個,它在內存中的效率會低得多,不是嗎? –