简体   繁体   中英

entity framework simple subquery generates ugly sql

I'm trying to optimize the following simple Entity Framework query to retreieve all the products from the same group

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;

After checking the generated sql using SQL Server Profiler I see this query

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)

Why is it generating so many identical JOINs? Is there any option to remove the final null casting? Could you please suggest ways to improve the generated sql?

I've tested also with LINQPad and that one is generating normal 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
    ))

If you're really dealing with a primary key (id) here, I'm not sure that you need the FirstOrDefault. Would the following accomplish the same goal:

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

And the generated SQL is

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]

Try the following, its two statements but should produce smoother SQL if that is what you are after:

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);
}

This assumes that Id is an int, if it is not, use the appropriate boundary check.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM