Mar*_*arc 6 .net c# linq linq-to-entities entity-framework
我有一个类方法:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
并评估表达
decimal? total =
(from cartItems in storeDB.Carts
where cartItems.CartId == shoppingCartId
select (int?)cartItems.Count * cartItems.Product.GetPrice(store.RateId))
.Sum();
Run Code Online (Sandbox Code Playgroud)
抛出异常:
LINQ to Entities无法识别方法'System.Decimal GetPrice(System.Guid)'方法,并且此方法无法转换为商店表达式.
我在其他地方使用这个相同的代码,工作得很好:
// Get the price for given rate
decimal price = product.GetPrice(rate.RateId);
Run Code Online (Sandbox Code Playgroud)
知道怎么解决吗?
Tho*_*que 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));
Run Code Online (Sandbox Code Playgroud)
GetPrice在SQL中没有等效项,因此您需要在结果上执行它,而不是直接在查询中执行它.AsEnumerable迫使Linq 从这一点开始将查询视为IEnumerable(而不是那个IQueryable),因此下一步将在内存中执行,而不是在DB中执行.
发生异常的原因是实体框架提供程序尝试为扩展方法创建SQL语句.当您单独使用该方法时,它只是为扩展方法的内容创建SQL,这很好.
除了GetPrice在"外部"查询的结果中调用导致N + 1查询的循环之外,我遇到的解决此问题的最佳方法是使用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();
Run Code Online (Sandbox Code Playgroud)
请注意,这会创建一个具有相同签名的表达式(除了它不能用作扩展方法),就像您拥有的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();
Run Code Online (Sandbox Code Playgroud)
该.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();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14712 次 |
| 最近记录: |