2011-07-30 55 views
6

我有一个类方法:方法用getPrice()不能被翻译成商店表达

public static class ProductExtensions { 

    public static decimal GetPrice(this Product product, Guid rateId) { 

     return product.Prices 
      .Where(p => p.Rate.RateId == rateId) 
      .Select(b => b.UnitPrice) 
      .DefaultIfEmpty(product.UnitPrice) 
      .First(); 
    } 
} 

和表达式的评估

 decimal? total = 
      (from cartItems in storeDB.Carts 
      where cartItems.CartId == shoppingCartId 
      select (int?)cartItems.Count * cartItems.Product.GetPrice(store.RateId)) 
      .Sum(); 

抛出异常:

LINQ实体无法识别方法'System.Decimal GetPrice(System.Guid)'方法,并且此方法不能转换为存储表达式。

我使用在其他地方这个非常相同的代码和工作得很好:

 // Get the price for given rate 
     decimal price = product.GetPrice(rate.RateId); 

任何想法如何解决呢?

回答

11

试一下:

decimal? total = 
     (from cartItems in storeDB.Carts 
     where cartItems.CartId == shoppingCartId 
     select new { cartItems.Count, cartItems.Product}) 
     .AsEnumerable() 
     .Sum(x => (int?)x.Count * cart.Product.GetPrice(store.RateId)); 

GetPrice在SQL不相等的,所以您需要在结果上执行它,而不是直接在查询中执行。 AsEnumerable强迫Linq从这一点考虑查询为IEnumerable(而不是IQueryable),所以接下来会在内存中执行,而不是在DB中执行。

+0

请注意,对于结果集中的每个项目,这将在GetPrice中执行一次子查询 –

+0

为什么-1?答案中有什么不对吗? –

5

发生异常的原因是实体框架提供程序试图为扩展方法创建SQL语句。当你使用方法本身时,它只是为扩展方法的内容创建SQL,这很好。

使用LinqKit

要使用它,你定义一个表达式我遇到过解决这个问题,除了在对“外”查询导致N + 1查询,结果循环中调用GetPrice的最佳方式树,而不是扩展方法,像这样:

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

注意,这将创建具有相同签名的表达式(但它不能被用作扩展方法)作为用getPrice方法你了。

要使用另一个结合这个表达式树,你需要LinqKit

decimal? total = 
    (from cartItems in storeDB.Carts 
    where cartItems.CartId == shoppingCartId 
    select (int?)cartItems.Count * 
     priceSelector.Invoke(cartItems.Product, store.RateId)) 
      .Expand() 
      .Sum(); 

.Invoke()调用增加了一个调用的表达式树。 Expand()调用内嵌此方法,因此您可以获得一个可以转换为SQL的大型表达式树。

这种方法将编写一个查询,看起来像下面的一个,但有一个可重复使用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(); 
相关问题