我在http://damieng.com/blog/2010/05/21/include-for-linq-to-sql-and-maybe-other-providers尝试了Include
扩展方法,但它并没有真正起作用。
所以我在Linq-to-SQL中有这个查询:
var items = dataContext.Items()
.Where(x => x.Id < 100)
.ToList();
并且数据上下文具有加载选项LoadWith(x => x.ItemImages)
。
产生这个SQL语句:
SELECT [t0].[Id], [t0].[Number], [t0].[Title], [t1].[Id] AS [Id2], [t1].[ItemId], [t1].[Url], (
SELECT COUNT(*)
FROM [dbo].[ItemImage] AS [t2]
WHERE [t2].[ItemId] = [t0].[Id]
) AS [value]
FROM [dbo].[Item] AS [t0]
LEFT OUTER JOIN [dbo].[ItemImage] AS [t1] ON [t1].[ItemId] = [t0].[Id]
WHERE [t0].[Id] < @p0
ORDER BY [t0].[Id], [t1].[Id]
现在,如果我不使用数据加载选项,但重写查询:
var items = dataContext.Items()
.Where(x => x.Id < 100)
.Select(x=>new Tuple<Item, EntitySet<ItemImage>>(x, x.ItemImages))
.AsEnumerable()
.Select(x=>x.Item1)
.ToList();
生成的SQL语句是相同的:
SELECT [t0].[Id], [t0].[Number], [t0].[Title], [t1].[Id] AS [Id2], [t1].[ItemId], [t1].[Url], (
SELECT COUNT(*)
FROM [dbo].[ItemImage] AS [t2]
WHERE [t2].[ItemId] = [t0].[Id]
) AS [value]
FROM [dbo].[Item] AS [t0]
LEFT OUTER JOIN [dbo].[ItemImage] AS [t1] ON [t1].[ItemId] = [t0].[Id]
WHERE [t0].[Id] < @p0
ORDER BY [t0].[Id], [t1].[Id]
但是,如果我正在访问items[0].ItemImages
属性,它会请求SQL Server检索项目图像,因此看起来它有所有必需的数据以避免其他查询,但是实现出错并且它仍然存在其他查询,虽然它可以避免它们。
我可以以某种方式解决这个问题吗?
更新:我对使用LoadWith选项的性能持怀疑态度,并认为执行两个查询(一个用于项目,第二个用于图像)和代码中的映射会比Linq2Sql生成单个SQL查询更快,但至少与我的数据量单个查询的工作速度更快,因此看到解决方案会非常有趣。
答案 0 :(得分:1)
我博客上的include方法仅以一对一的关系进行演示和测试。
通过投影引用一对一的查询,它填充LINQ to SQL身份缓存。稍后导航任何导航属性时,它将首先点击该缓存。
不幸的是,LINQ to SQL不够先进,不能以这种方式缓存到多个关联。
您可以选择使用LoadWith或编写项目和分组的查询,例如
var items = dataContext.ItemImages()
.Where(x => x.Item.Id < 100)
.Select(x => new Tuple<ItemImage, Item>(x, x.Item))
.AsEnumerable()
.Select(x = > x.Item1)
.GroupBy(x => x.Item);
此查询的警告是您不会看到任何没有ItemImages的项目。