LINQ is generating SQL with two joins when I only want one
If you have a lot of conditions in your LINQ statement, sometimes LINQ-to-SQL does it wrong:
var query = from
pp in Context.ProductPrices
where
productCodes.Contains(pp.Product.ProductCode) &&
pp.PriceList == priceList &&
pp.Product.AccountNumber == customer.AccountNumber
select new { Price = pp.Price, ProductCode = pp.Product.ProductCode }
Generates this:
SELECT
1 AS [C1],
[Extent1].[Price] AS [Price],
[Extent3].[ProductCode] AS [ProductCode],
...
[Extent3].[Colour] AS [Colour]
FROM [dbo].[ProductPrice] AS [Extent1]
INNER JOIN [aop].[CustomerProduct] AS [Extent2] ON [Extent1].[ProductCode] = [Extent2].[ProductCode]
LEFT OUTER JOIN [aop].[CustomerProduct] AS [Extent3] ON [Extent1].[ProductCode] = [Extent3].[ProductCode]
WHERE (N'ABC123' = [Extent1].[ProductCode]) AND ([Extent1].[PriceList] = @p__linq__0) AND ([Extent2].[AccountNumber] = @p__linq__1)
Notice how there is both an inner join and a left outer join on CustomerProduct. This is because of the repeated use of pp.Product in the query.
How to fix it
Use LINQ’s let keyword to cache the result of the property access:
var query = from
pp in Context.ProductPrices
let
prod = pp.Product
where
productCodes.Contains(prod.ProductCode) &&
pp.PriceList == priceList &&
prod.AccountNumber == customer.AccountNumber
select new { Price = pp.Price, ProductCode = prod.ProductCode }
Now you can safely re-use the prod variable as many times as you want in the query and LINQ will always use the same database entity instead of creating another join.
SELECT
1 AS [C1],
[Extent1].[Price] AS [Price],
[Extent2].[ProductCode] AS [ProductCode],
...
[Extent2].[Colour] AS [Colour]
FROM [dbo].[ProductPrice] AS [Extent1]
INNER JOIN [aop].[CustomerProduct] AS [Extent2] ON [Extent1].[ProductCode] = [Extent2].[ProductCode]
WHERE (N'ABC123' = [Extent2].[ProductCode]) AND ([Extent1].[PriceList] = @p__linq__0) AND ([Extent2].[AccountNumber] = @p__linq__1)
So you can see the adjusted query doesn’t generate an Extent3 at all, which is much better!