2009-08-31 65 views
3

剛剛從Subsonic 2.2 ActiveRecord更新爲3.0.0.3。我試圖使用LINQ做一個分頁查找這樣的查詢(我的對象/表被稱爲「庫」):Subsonic 3.0.0.3使用Linq的SQL分頁

Repository.Find(item => item.DocumentTitle.Contains(searchTerm)) 
    .OrderBy(i => i.DocumentTitle).Skip((currentPage - 1) * itemsPerPage) 
    .Take(itemsPerPage); 

當我認爲通過使用SQL Server Profiler此查詢生成的SQL,沒有在SQL中分頁,所有的分頁都在C#中的內存中完成。現在,Subsonic查詢語言確實有一個很好的GetPaged過程,但是我認爲LINQ本應該這樣做。我在這裏錯過了什麼,或者這是LINQ的限制嗎?

我知道Repository.GetPaged()函數,但沒有足夠的參數 - 我需要做一個動態排序,以及一個Find()

回答

5

在做進一步的測試,這種說法正確工作:

(from i in dataContext.Repositories 
where i.DocumentTitle.Contains(searchTerm) 
orderby i.DateCreated ascending select i) 
.Skip((currentPage - 1) * itemsPerPage).Take(itemsPerPage); 

執行時,上面的LINQ聲明傷愈復出正確的SQL分頁。

,我可以得出的唯一結論是,當你正使用方法鏈接語法,一旦你的初始LAMDA表達

Repository.Find(item => item.DocumentTitle.Contains(searchTerm)) 

亞音速SQL解釋停止創造鏈上的任何方法SQL外end

.OrderBy(i => i.DocumentTitle).Skip(15).Take(10); 

或者,我在這裏完全做錯了什麼?任何人都有一些見解?

+0

做了更多的研究。顯然,這是由於C#如何編譯linq表達式。編譯器必須在設計時知道聲明的內容。如果沒有,SubSonic「ExpressionVisitor」(這不是SubSonic獨有的)不能反映該語句,因爲它不再是單個「表達式」。 – Steve 2009-09-08 13:43:39

+0

這裏有第三方庫可以讓你在多個步驟中構建你的linq語句,但是增加了更多的外部依賴項到你的項目中。 SubSonic實際上似乎已經具備了其中的一些功能,但目前我還不太瞭解,所以提出了一種方法來使用它們來實現這一點。 – Steve 2009-09-08 13:44:28

1

您可以通過添加「遞減」的排序字段來挑選GetPaged,但是......

尋呼應該努力 - 我看着在我面前的分頁SQL,它不是在內存中完成。你如何測試這個?如果使用將執行查詢的「ToList()」,那麼請查看分析器。

+0

GetPaged函數將是理想的,除了我需要它執行一個Find()以及FindGetPaged(),如果你願意的話。 這是我看到我發佈的查詢通過的SQL(我也試過ToList (),我已經將IEnumerable傳遞給ListView數據源): exec sp_executesql N'SELECT [t0]。[CategoryName] ,[t0]。[DateCreated],[t0]。[DocumentFileType],[t0]。[DocumentTitle],[t0]。[FileContent],[t0]。[RepositoryId] FROM [dbo]。[mag_Repository] ​​AS t0 WHERE([t0]。[DocumentTitle] LIKE''%''+ @ p0 +''%'')',N'@ p0 nvarchar(4000)',@ p0 = N'' – Steve 2009-09-01 13:04:53

+0

爲了測試它I附加VS調試器,啓動只用於我的DB的分析器,然後在此函數中斷開: 列表 retList =版本庫 。找到(item => item.DocumentTitle.Contains(searchTerm)) .OrderByDescending(i => i.DocumentTitle) .Skip((currentPage - 1)* itemsPerPage) .Take(itemsPerPage).ToList (); 並觀看sql語句通過配置文件時,我打F10。 – Steve 2009-09-01 13:07:12

+0

我也對GetPaged做了一個測試,以確保我看到了SQL的正確性,並且通過RowNumber()分頁sql語句正確使用了。所以我很難理解我在這裏做錯了什麼。 – Steve 2009-09-01 13:35:01

0

有點晚了,但...

Repository.Find() 

返回的IList所以執行查詢,因此SQL執行無分頁然後

.Skip(x).Take(x) 

是在內存中完成。 嘗試

Repository.All().Where(expression).Skip(x).Take(x) 

所有這些返回IQueryable的和非列舉的對象,因此尋呼是在SQL中使用ROW_NUMBER()函數來完成。

說了亞音速3簡單的存儲庫中生成以下SQL

exec sp_executesql N'SELECT [t0].[Id], [t0].[IsDeleted], [t0].[Name], [t0].[ParentUuid], [t0].[Uuid] 
FROM (SELECT [t1].[Id], [t1].[IsDeleted], [t1].[Name], [t1].[ParentUuid], ROW_NUMBER() OVER() AS rownum, [t1].[Uuid] 
FROM [Sites] AS t1 
WHERE (([t1].[ParentUuid] = @p0) AND ([t1].[IsDeleted] = 0))) AS t0 
WHERE [t0].[rownum] BETWEEN (20 + 1) AND (20 + 10)',N'@p0 uniqueidentifier',@p0='00000000-0000-0000-0000-000000000000' 

它拋出一個異常

Unhandled Exception: System.Data.SqlClient.SqlException: The ranking function "ROW_NUMBER" must have an ORDER BY clause. 

所以它似乎有在亞音速:-(錯誤

+0

我不會說這是一個SubSonic錯誤,因爲SubSonic會將您的查詢轉換爲普通的sql。由於異常告訴你ROW_NUMBER必須有一個ORDER BY子句,所以你必須添加一個orderby關鍵字到你的linq查詢中,所以subsonic也會生成一個order(順便說一句,mysql在這種情況下不會拋出異常,因爲LIMIT(x ,y)不需要ORDER BY – 2010-10-07 13:45:10

+0

也許不是一個bug,我同意了,我已經更新了一個subsonic的本地構建,以測試一個order by子句是否已經添加到包含ROW_NUMBER函數的任何查詢中,如果沒有order我將ORDER BY Id插入到ROW_NUMBER的OVER部分,從而避免了異常。它並不理想,並且它是特定於環境的(我的所有DOM類必須繼承DomBase,並且會有一個ID屬性)。 – 2010-10-15 09:59:59

相關問題