方法GetPrice()无法转换为商店表达式

时间:2011-07-30 20:36:37

标签: c# .net linq entity-framework linq-to-entities

我有一个班级方法:

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 to Entities无法识别方法'System.Decimal GetPrice(System.Guid)'方法,并且此方法无法转换为商店表达式。

我在其他地方使用这个相同的代码并且运行得很好:

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

知道怎么解决吗?

2 个答案:

答案 0 :(得分: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),因此下一步将在内存中执行,而不是在数据库中执行。

答案 1 :(得分:5)

发生异常的原因是实体框架提供程序尝试为扩展方法创建SQL语句。当您单独使用该方法时,它只是为扩展方法的内容创建SQL,它可以正常工作。

我遇到的解决此问题的最佳方法,除了在导致N + 1查询的“外部”查询结果的循环中调用GetPrice之外,正在使用LinqKit

要使用它,您可以定义表达式树,而不是像这样的扩展方法:

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