使用TOP和Between时,Linq to SQL提供了不同的结果

时间:2010-01-05 14:33:41

标签: linq-to-sql paging sql-order-by

我正在使用Linq to Sql(实际上它是Dynamic Linq to SQL,允许你在运行时传递字符串where子句,orderby等)但是我得到了一些不同的结果,它似乎是基于是否底层T-SQL使用TOP关键字或使用BETWEEN。

我试图把问题分解成一个小例子,这是场景:

我正在使用一个存储库模式和以下方法,只需将两个表连接到左外连接。

   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

这是我所期待的。但是page1包含

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

这是我所期望的,它是第6至10项。

page1的底层T-SQL是

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)

第2页的底层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中时,我得到了我所描述的结果。如果我使用page2 T-SQL并修改了行

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

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

我得到了我对第1页的期望。即前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)和分页(跳过并采取),并且需要相当一般地处理它。

  • 有没有办法强制使用LINQ BETWEEN 语法而不是 TOP
  • 我应该接近这个吗? 不同?

长篇大论道歉。

此致 西蒙

1 个答案:

答案 0 :(得分:0)

无论SQL是如何生成的(LINQ或其他),如果ORDER BY列具有重复值,则每次运行查询时都可以得到不同的结果。

当您ORDER BY [t3].[value]对包含许多重复值的列进行排序时。

您可以通过从Management Studio运行非常简单的SQL SELECT来测试它。每次运行它,你都会得到不同的结果。

获得一致结果的一种方法是使用ROW_NUMBER。或者,将任何其他列添加到唯一的ORDER BY将导致结果始终以相同的顺序返回。这个其他专栏是否与您的查询有关并不重要,只是它是唯一的。