Version 3.1
Build: May 13, 2011
DB: SQL Server 2008 R2 using Adapter model
Summary
TakePage in LINQ to LLBLGen isn't doing paging at the SQL Server when the query has a left join and coalesce orderby expression.
Problem Query
The query below highlights the problem. It uses TakePage and it has a left join with a coalesce order by expression. I know I am not using the left join, but I've simplified the query by removing the where clause for this example.
List<LearningProductEntity> products =
(from lp in metaData.LearningProduct
join lpt in metaData.LearningProductTag on lp.Id equals lpt.ProductId into tags
from t in tags.DefaultIfEmpty()
orderby lp.NoteworthyDate ?? lp.UpdatedUtc
select lp).TakePage(2, 10).ToList();
Resulting SQL
This result shows that the paging did not occur at SQL Server.
SELECT [LPA_L1].[AllowsComments], [LPA_L1].[AlternateIdInbound], [LPA_L1].[AlternateIdOutbound], [LPA_L1].[DefaultTermDays], [LPA_L1].[DescriptionHtml], [LPA_L1].[ExpirationDate], [LPA_L1].[IconFilename], [LPA_L1].[Id], [LPA_L1].[NoteworthyDate], [LPA_L1].[OrganizationAlternateId], [LPA_L1].[OrganizationId], [LPA_L1].[PreviewMediaHeight], [LPA_L1].[PreviewMediaMP4VideoFilename] AS [PreviewMediaMp4VideoFilename], [LPA_L1].[PreviewMediaPosterImageFilename], [LPA_L1].[PreviewMediaWidth], [LPA_L1].[PublishedUTC] AS [PublishedUtc], [LPA_L1].[Rate1], [LPA_L1].[Rate2], [LPA_L1].[TeaserHtml], [LPA_L1].[Title], [LPA_L1].[TypeId], [LPA_L1].[UpdatedByLearnerId], [LPA_L1].[UpdatedUTC] AS [UpdatedUtc] FROM ( [Nucleus].[Learning].[Product] [LPA_L1] LEFT JOIN [Nucleus].[Learning].[ProductTag] [LPA_L2] ON [LPA_L1].[Id] = [LPA_L2].[ProductId]) ORDER BY COALESCE([LPA_L1].[NoteworthyDate], [LPA_L1].[UpdatedUTC]) ASC
Query without Coalesce Orderby
If I change the orderby expression to be a simple orderby (instead of a coalesce), then the paging does occur at SQL Server.
List<LearningProductEntity> products =
(from lp in metaData.LearningProduct
join lpt in metaData.LearningProductTag on lp.Id equals lpt.ProductId into tags
from t in tags.DefaultIfEmpty()
orderby lp.NoteworthyDate
select lp).TakePage(2, 10).ToList();
Resulting SQL
This result shows that the paging did occur at SQL Server.
exec sp_executesql N'WITH __actualSet AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) AS __rowcnt FROM (SELECT DISTINCT TOP 20 [LPA_L1].[AllowsComments], [LPA_L1].[AlternateIdInbound], [LPA_L1].[AlternateIdOutbound], [LPA_L1].[DefaultTermDays], [LPA_L1].[DescriptionHtml], [LPA_L1].[ExpirationDate], [LPA_L1].[IconFilename], [LPA_L1].[Id], [LPA_L1].[NoteworthyDate], [LPA_L1].[OrganizationAlternateId], [LPA_L1].[OrganizationId], [LPA_L1].[PreviewMediaHeight], [LPA_L1].[PreviewMediaMP4VideoFilename] AS [PreviewMediaMp4VideoFilename], [LPA_L1].[PreviewMediaPosterImageFilename], [LPA_L1].[PreviewMediaWidth], [LPA_L1].[PublishedUTC] AS [PublishedUtc], [LPA_L1].[Rate1], [LPA_L1].[Rate2], [LPA_L1].[TeaserHtml], [LPA_L1].[Title], [LPA_L1].[TypeId], [LPA_L1].[UpdatedByLearnerId], [LPA_L1].[UpdatedUTC] AS [UpdatedUtc] FROM ( [Nucleus].[Learning].[Product] [LPA_L1] LEFT JOIN [Nucleus].[Learning].[ProductTag] [LPA_L2] ON [LPA_L1].[Id] = [LPA_L2].[ProductId]) ORDER BY [LPA_L1].[NoteworthyDate] ASC) AS _tmpSet) SELECT [AllowsComments], [AlternateIdInbound], [AlternateIdOutbound], [DefaultTermDays], [DescriptionHtml], [ExpirationDate], [IconFilename], [Id], [NoteworthyDate], [OrganizationAlternateId], [OrganizationId], [PreviewMediaHeight], [PreviewMediaMp4VideoFilename], [PreviewMediaPosterImageFilename], [PreviewMediaWidth], [PublishedUtc], [Rate1], [Rate2], [TeaserHtml], [Title], [TypeId], [UpdatedByLearnerId], [UpdatedUtc] FROM __actualSet WHERE [__rowcnt] > @p1 AND [__rowcnt] <= @p2 ORDER BY [__rowcnt] ASC',N'@p1 int,@p2 int',@p1=10,@p2=20
Expected SQL
I would expect the following SQL statement when using LINQ statement at the top of this thread. The coalesce requires an additional select column (I think).
exec sp_executesql N'
WITH __actualSet AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) AS __rowcnt FROM (
SELECT DISTINCT TOP 20
[LPA_L1].[AllowsComments], [LPA_L1].[AlternateIdInbound], [LPA_L1].[AlternateIdOutbound],
[LPA_L1].[DefaultTermDays], [LPA_L1].[DescriptionHtml], [LPA_L1].[ExpirationDate],
[LPA_L1].[IconFilename], [LPA_L1].[Id], [LPA_L1].[NoteworthyDate],
[LPA_L1].[OrganizationAlternateId], [LPA_L1].[OrganizationId], [LPA_L1].[PreviewMediaHeight],
[LPA_L1].[PreviewMediaMP4VideoFilename] AS [PreviewMediaMp4VideoFilename],
[LPA_L1].[PreviewMediaPosterImageFilename], [LPA_L1].[PreviewMediaWidth],
[LPA_L1].[PublishedUTC] AS [PublishedUtc], [LPA_L1].[Rate1], [LPA_L1].[Rate2],
[LPA_L1].[TeaserHtml], [LPA_L1].[Title], [LPA_L1].[TypeId], [LPA_L1].[UpdatedByLearnerId],
[LPA_L1].[UpdatedUTC] AS [UpdatedUtc]
-- ***** MISSING THIS IN THE SELECT. REQUIRED BY COALESCE ORDER BY ********
,COALESCE([LPA_L1].[NoteworthyDate], [LPA_L1].[UpdatedUTC]) as SomeGeneratedColumnName
FROM ( [Nucleus].[Learning].[Product] [LPA_L1] LEFT JOIN [Nucleus].[Learning].[ProductTag] [LPA_L2] ON [LPA_L1].[Id] = [LPA_L2].[ProductId])
-- ***** COALESCE ORDER BY **********
order by COALESCE([LPA_L1].[NoteworthyDate], [LPA_L1].[UpdatedUTC]) ASC
) AS _tmpSet) SELECT [AllowsComments], [AlternateIdInbound], [AlternateIdOutbound], [DefaultTermDays], [DescriptionHtml], [ExpirationDate], [IconFilename], [Id], [NoteworthyDate], [OrganizationAlternateId], [OrganizationId], [PreviewMediaHeight], [PreviewMediaMp4VideoFilename], [PreviewMediaPosterImageFilename], [PreviewMediaWidth], [PublishedUtc], [Rate1], [Rate2], [TeaserHtml], [Title], [TypeId], [UpdatedByLearnerId], [UpdatedUtc] FROM __actualSet WHERE [__rowcnt] > @p1 AND [__rowcnt] <= @p2 ORDER BY [__rowcnt] ASC',N'@p1 int,@p2 int',@p1=10,@p2=20