如何在EF查询中用函数参数化选择器
本文关键字:函数 参数 选择器 EF 查询 | 更新日期: 2023-09-27 18:00:07
我有一个投影函数,我将它传递给IQueryable<>.Select()
方法:
private static Expression<Func<VendorPrice, PriceItem>> GetPriceSelector(){
return e => new PriceItem {
Id = e.Id,
Price = Math.Round(e.Price, 4)
};
}
一切都很好,但我想这样参数化它:
private static Expression<Func<VendorPrice, PriceItem>> GetPriceSelector(Func<VendorPrice, decimal> formula){
return e => new PriceItem {
Id = e.Id,
Price = formula(e)
};
}
这样我就可以称之为
prices.Select(GetPriceSelector(e => Math.Round(e.Price, 4)))
不幸的是,EF对此颇有怨言:
LINQ to中不支持LINQ表达式节点类型"Invoke"实体
如何重写代码让EF开心?
首先,GetPriceSelector
方法需要接受一个表达式,而不是函数。不同之处在于,表达式是作为数据的代码,因此可以转换为SQL,而函数是编译代码,因此无法转换为SQL。
接下来,您需要一种方法来合并这两个表达式。手动操作很难。幸运的是,有一个名为LINQKit的库可以做到这一点。以下是使用LINQKit解决问题的方法:
private static Expression<Func<VendorPrice, PriceItem>> GetPriceSelector(
Expression<Func<VendorPrice, decimal>> formula)
{
Expression<Func<VendorPrice, PriceItem>> expression = e => new PriceItem
{
Id = e.Id,
Price = formula.Invoke(e) //use the forumla expression here
};
return expression.Expand(); //This causes formula.Invoke(e) to be converted
//to something like Math.Round(e.Price, 4)
}