2010-01-05 70 views
1

我使用Linq to Sql(實際上它是Dynamic Linq to SQL,允許您在運行時爲where子句,orderby等傳遞字符串)但是我得到一些不同的結果,它似乎是基於底層T-SQL是使用TOP關鍵字還是使用BETWEEN。Linq to SQL提供了不同的結果,當使用TOP和

我試圖破解的問題分解成一個小例子,這裏的情景:

我使用一個倉庫模式,簡單地連接2臺與左外下面的方法加入。

public IQueryable<TestGalleryViewModel> FetchGalleryItems() 
    { 

     var galleryItems = from painting in Gallery 
          join artist in Artists 
           on painting.ArtistID equals artist.ArtistID 

          into paintingArtists 
          from artist in paintingArtists.DefaultIfEmpty() 

          select new TestGalleryViewModel 
          { 

           Id = painting.PaintingID, 
           ArtistName = artist == default(Artist) ? "" : artist.Surname + " " + artist.Forenames, 
          }; 

     return galleryItems; 
    } 

然後我有一個使用FetchGalleryItems方法一個小的測試方法:

 var query = respository.Test_FetchGalleryItems().Where("ArtistName.Contains(\"Adams Charles James\")"); 

     var orderedlist = query.OrderBy("ArtistName asc"); 
     var page1 = orderedlist.Skip(0).Take(5); 
     var page2 = orderedlist.Skip(5).Take(5); 

的orderedList包含以下基本的價值觀:

176 ADAMS Charles James 
620 ADAMS Charles James 
621 ADAMS Charles James 
660 ADAMS Charles James 
683 ADAMS Charles James 
707 ADAMS Charles James 
735 ADAMS Charles James 
739 ADAMS Charles James 
740 ADAMS Charles James 
741 ADAMS Charles James 

這是我期望的那樣。但第1頁包含

707 ADAMS Charles James 
683 ADAMS Charles James 
660 ADAMS Charles James 
621 ADAMS Charles James 
620 ADAMS Charles James 

正如你可以看到的是第5個項目。第2頁包含

707 ADAMS Charles James 
735 ADAMS Charles James 
739 ADAMS Charles James 
740 ADAMS Charles James 
741 ADAMS Charles James 

WHIS是我所期望的,它是項目6至10

底層的T-SQL的第1頁是

SELECT TOP (5) [t3].[PaintingID] AS [Id], [t3].[value] AS [ArtistName] 
FROM (
    SELECT [t0].[PaintingID], 
     (CASE 
      WHEN [t2].[test] IS NULL THEN CONVERT(NVarChar(101),'') 
      ELSE ([t2].[Surname] + ' ') + [t2].[Forenames] 
     END) AS [value] 
    FROM [dbo].[Gallery] AS [t0] 
    LEFT OUTER JOIN (
     SELECT 1 AS [test], [t1].[ArtistID], [t1].[Surname], [t1].[Forenames] 
     FROM [dbo].[Artists] AS [t1] 
     ) AS [t2] ON [t0].[ArtistID] = ([t2].[ArtistID]) 
    ) AS [t3] 
WHERE [t3].[value] LIKE '%Adams Charles James%' 
ORDER BY [t3].[value] 

注意到它的使用TOP(5)

page2的底層T-SQL是

SELECT [t4].[PaintingID] AS [Id], [t4].[value] AS [ArtistName] 
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY [t3].[value], [t3].[Surname], [t3].[Forenames]) AS [ROW_NUMBER], [t3].[PaintingID], [t3].[value] 
    FROM (
     SELECT [t0].[PaintingID], 
      (CASE 
       WHEN [t2].[test] IS NULL THEN CONVERT(NVarChar(101),'') 
       ELSE ([t2].[Surname] + ' ') + [t2].[Forenames] 
      END) AS [value], [t2].[Surname], [t2].[Forenames] 
     FROM [dbo].[Gallery] AS [t0] 
     LEFT OUTER JOIN (
      SELECT 1 AS [test], [t1].[ArtistID], [t1].[Surname], [t1].[Forenames] 
      FROM [dbo].[Artists] AS [t1] 
      ) AS [t2] ON [t0].[ArtistID] = ([t2].[ArtistID]) 
     ) AS [t3] 
    WHERE [t3].[value] LIKE '%Adams Charles James%' 
    ) AS [t4] 
WHERE [t4].[ROW_NUMBER] BETWEEN 5 + 1 AND 5 + 5 
ORDER BY [t4].[ROW_NUMBER] 

注意到它的使用BETWEEN

當我粘貼T-SQL命令插入到的SQL Express Management Studio中,我得到我所描述的結果。如果我用的第2頁T-SQL和修正線

WHERE [t4].[ROW_NUMBER] BETWEEN 5 + 1 AND 5 + 5 

WHERE [t4].[ROW_NUMBER] BETWEEN 1 AND 5 

我得到我所期待的第一頁的結果。即前5個項目。

176 ADAMS Charles James 
620 ADAMS Charles James 
621 ADAMS Charles James 
660 ADAMS Charles James 
683 ADAMS Charles James 

所以,簡而言之,當T-SQL使用之間,而不是TOP我得到我預期的效果。我在我的應用程序中使用過濾(where子句),排序(orderBy)和分頁(skip and take),並且需要相當一般地處理這個問題。

  • 有沒有辦法迫使LINQ使用 的之間語法而不是 TOP
  • 我是否應該以不同的方式接近此 ?

道歉的長期職位。

問候, 西蒙

+0

請注意,您在第二個SQL查詢中有不同的Order By Clause。嘗試評估var orderedlist = query.OrderBy(「ArtistName asc」)。ToList();首先是 。然後從那裏獲取頁面。 – 2010-01-05 14:45:20

回答

0

不管SQL是如何產生的(LINQ或其他方式),如果你ORDER BY具有重複值的列,你可以得到每次運行查詢時不同的結果。

當您對ORDER BY [t3].[value]進行排序時,您正在對包含許多重複值的列進行排序。

您可以通過從Management Studio運行一個非常簡單的SQL SELECT來測試。每次運行它時,都會得到不同的結果。

獲得一致結果的一種方法是像您所做的那樣使用ROW_NUMBER。或者,將任何其他列添加到唯一的ORDER BY將導致結果始終以相同的順序返回。這個列與您的查詢是否有關係並不重要,只是它是唯一的。

+0

謝謝DOK, 你說一種獲得一致性reults的方法是使用「ROW_NUMBER」,因爲你已經完成了。事實上,我沒有使用ROW_NUMBER,LINQ to Sql生成了該代碼,我似乎沒有任何控制權。這真的是我的問題 - 我可以告訴linq sql以使用「row_number」和「between」而不是「TOP」作爲第一頁。最後,我必須爲我的所有實體添加一個獨特的列,並按照您的建議在我的order by子句的末尾添加一行。我已經在想些什麼,但想知道是否有更好的解決方案。感謝您的回覆。 – 2010-01-05 15:38:33

相關問題