【发布时间】:2012-02-28 02:13:38
【问题描述】:
我有可以处理多对多关系的 Linq-to-SQL 代码,但请注意,关系本身有自己的一组属性(在这种情况下,产品属于许多类别,并且每个产品在-category 关系有自己的 SortOrder 属性)。
我有一个 Linq-to-SQL 块,它返回具有类别成员资格信息的匹配产品。当我执行代码时,它会生成优化的 T-SQL 代码,如下所示:
exec sp_executesql N'SELECT [t0].[ProductId], [t0].[Name], [t1].[ProductId] AS [ProductId2], [t1].[CategoryId], [t1].[SortOrder] AS [SortOrder2], [t2].[CategoryId] AS [CategoryId2], [t2].[Name] AS [Name2] (
SELECT COUNT(*)
FROM [dbo].[ProductsInCategories] AS [t3]
INNER JOIN [dbo].[Categories] AS [t4] ON [t4].[CategoryId] = [t3].[CategoryId]
WHERE [t3].[ProductId] = [t0].[ProductId]
) AS [value]
FROM [dbo].[Products] AS [t0]
LEFT OUTER JOIN ([dbo].[ProductsInCategories] AS [t1]
INNER JOIN [dbo].[Categories] AS [t2] ON [t2].[CategoryId] = [t1].[CategoryId]) ON [t1].[ProductId] = [t0].[ProductId]
WHERE (([t0].[OwnerId]) = @p0) AND ([t0].[Visible] = 1)
ORDER BY [t0].[SortOrder], [t0].[Name], [t0].[ProductId], [t1].[CategoryId]',N'@p0 bigint',@p0=3
但是,当我向 Linq 表达式添加分页指令(即“.Skip(0).Take(50)”)时,生成的 SQL 变为:
exec sp_executesql N'SELECT TOP (50) [t0].[ProductId], [t0].[Name]
FROM [dbo].[Products] AS [t0]
WHERE (([t0].[OwnerId]) = @p0) AND ([t0].[Visible] = 1)
ORDER BY [t0].[SortOrder], [t0].[Name]',N'@p0 bigint',@p0=3
这意味着不再加载类别成员信息,因此 Linq-to-SQL 然后将手动加载代码执行 50 次(返回集中的每个成员一个):
exec sp_executesql N'SELECT [t0].[ProductId], [t0].[CategoryId], [t0].[SortOrder], [t1].[CategoryId] AS [CategoryId2], [t1].[Name]
FROM [dbo].[ProductsInCategories] AS [t0]
INNER JOIN [dbo].[Categories] AS [t1] ON [t1].[CategoryId] = [t0].[CategoryId]
WHERE [t0].[ProductId] = @x1',N'@x1 bigint',@x1=1141
(显然,“@x1”ID 参数因原始查询的每个结果而异)。
很明显,Linq 分页会中断查询并导致它单独加载数据。有没有办法解决这个问题,或者我应该在自己的软件中进行分页?
...幸运的是,数据库中的产品数量足够少(可能有数万种产品,而这只是这不是一个好的查询。
编辑:
这是我的 Linq:
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Product>( p => p.ProductsInCategories );
dlo.LoadWith<ProductsInCategory>( pic => pic.Category );
this.LoadOptions = dlo;
query = from p in this.Products
select p;
// The lines below are added conditionally:
query = query.OrderBy( p => p.SortOrder ).ThenBy( p => p.Name );
query = query.Where( p => p.Visible );
query = query.Where( p => p.Name.Contains( filter ) || p.Description.Contains( filter ) );
query = query.Where( p => p.OwnerId == siteId );
skip/take 行是可选添加的,并且是导致不同 T-SQL 生成的唯一差异(据我所知):
IQueryable<Product> query = GetProducts( siteId, category, filter, showHidden, sortBySortOrder );
///////////////////////////////////
total = query.Count();
var pagedProducts = query.Skip( pageIndex * pageSize ).Take( pageSize );
return pagedProducts;
【问题讨论】:
标签: c# sql linq linq-to-sql