[英]entity framework simple subquery generates ugly sql
我正在尝试优化以下简单的Entity Framework查询,以检索同一组中的所有产品
var query = from p in ctx.Products
where p.GroupId == ( from q in ctx.Products
where q.Id == new Guid(".....")
select q.GroupId).FirstOrDefault()
select p;
使用SQL Server Profiler检查生成的sql后,我看到此查询
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[GroupId] AS [GroupId],
[Extent1].[Name] AS [Name],
[Extent1].[Code] AS [Code]
FROM [inv].[Products] AS [Extent1]
LEFT OUTER JOIN (SELECT TOP (1) [Extent2].[GroupId] AS [GroupId]
FROM [inv].[Products] AS [Extent2]
WHERE cast('.....' as uniqueidentifier) = [Extent2].[Id] ) AS [Limit1] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent3].[GroupId] AS [GroupId]
FROM [inv].[Products] AS [Extent3]
WHERE cast('.....' as uniqueidentifier) = [Extent3].[Id] ) AS [Limit2] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent4].[GroupId] AS [GroupId]
FROM [inv].[Products] AS [Extent4]
WHERE cast('.....' as uniqueidentifier) = [Extent4].[Id] ) AS [Limit3] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent5].[GroupId] AS [GroupId]
FROM [inv].[Products] AS [Extent5]
WHERE cast('.....' as uniqueidentifier) = [Extent5].[Id] ) AS [Limit4] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent6].[Id] AS [Id]
FROM [inv].[Products] AS [Extent6]
WHERE cast('.....' as uniqueidentifier) = [Extent6].[Id] ) AS [Limit5] ON 1 = 1
LEFT OUTER JOIN (SELECT TOP (1) [Extent7].[Id] AS [Id]
FROM [inv].[Products] AS [Extent7]
WHERE cast('.....' as uniqueidentifier) = [Extent7].[Id] ) AS [Limit6] ON 1 = 1
WHERE ([Extent1].[GroupId] = (CASE WHEN ([Limit1].[GroupId] IS NULL)
THEN cast('00000000-0000-0000-0000-000000000000' as uniqueidentifier)
ELSE [Limit2].[GroupId] END))
AND (CASE WHEN ([Limit3].[GroupId] IS NULL)
THEN cast('00000000-0000-0000-0000-000000000000' as uniqueidentifier)
ELSE [Limit4].[GroupId] END IS NOT NULL)
为什么会生成这么多相同的JOIN? 是否可以删除最终的空类型转换? 您能否提出一些改进生成的sql的方法?
我也用LINQPad进行了测试,并且正在生成普通的SQL
-- Region Parameters
DECLARE @p0 UniqueIdentifier = '....'
-- EndRegion
SELECT [t0].[Id], [t0].[GroupId], [t0].[Name], [t0].[Description], [t0].[Code]
FROM [inv].[Products] AS [t0]
WHERE [t0].[GroupId] = ((
SELECT TOP (1) [t1].[GroupId]
FROM [inv].[Products] AS [t1]
WHERE [t1].[Id] = @p0
))
如果您确实在这里处理主键(id),则不确定您是否需要FirstOrDefault。 以下内容是否可以实现相同的目标:
var query = from groupProduct in ctx.Products
where groupProduct.Id == someGuid // This should return only one result
join childProduct in ctx.Products
on groupProduct.Id equals childProduct.GroupId
select childProduct
生成的SQL是
SELECT
[Extent2].[Id] AS [Id],
[Extent2].[GroupId] AS [GroupId],
[Extent2].[Name] AS [Name],
[Extent2].[Code] AS [Code]
FROM [inv].[Products] AS [Extent1]
INNER JOIN [inv].[Products] AS [Extent2] ON [Extent1].[Id] = [Extent2].[GroupId]
WHERE cast('....' as uniqueidentifier) = [Extent1].[Id]
尝试以下两个语句,但是如果您要这样做,则应产生更平滑的SQL:
var groupId = ctx.Products.Where(p=> p.Id = new Guid(...).Select(p=> p.GroupId).FirstOrDefault();
if(groupId.HasValue)
{
var query = ctx.Products.Where(p=> p.GroupId == groupId).Select(p=> p);
}
假定Id是一个int,如果不是,则使用适当的边界检查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.