The reason the exception is thrown is because the Entity Framework provider is trying to create SQL queries for the extension method. When you use this method on its own, it simply creates SQL for the contents of the extension method, which works great.
The best way I came across is to fix this, besides calling GetPrice in the result loop of the βexternalβ query calling the N + 1 query, uses LinqKit
To use it, you define an expression tree instead of an extension method as follows:
static Expression<Func<Product, Guid, decimal>> priceSelector = (product, rateId) => product.Prices .Where(p => p.Rate.RateId == rateId) .Select(b => b.UnitPrice) .DefaultIfEmpty(product.UnitPrice) .First();
Note that this creates an expression with the same signature (except that it cannot be used as an extension method) as the GetPrice method you had.
To combine this expression tree with another, you need LinqKit :
decimal? total = (from cartItems in storeDB.Carts where cartItems.CartId == shoppingCartId select (int?)cartItems.Count * priceSelector.Invoke(cartItems.Product, store.RateId)) .Expand() .Sum();
Calling .Invoke() adds a call to the expression tree. Calling Expand() enables this method, so you get one large expression tree that can be converted to SQL.
This approach will write a query similar to the following, but with a reusable priceSelector :
decimal ? total = (from cartItems in storeDB.Carts where cartItems.CartId == shoppingCartId select (int?)cartItems.Count * product.Prices .Where(p => p.Rate.RateId == rateId) .Select(b => b.UnitPrice) .DefaultIfEmpty(product.UnitPrice) .First()).Sum();
source share