I have a projection function that I pass to IQueryable<>.Select()
method:
private static Expression<Func<VendorPrice, PriceItem>> GetPriceSelector(){
return e => new PriceItem {
Id = e.Id,
Price = Math.Round(e.Price, 4)
};
}
Everything works just fine but I want to parameterize it like that:
private static Expression<Func<VendorPrice, PriceItem>> GetPriceSelector(Func<VendorPrice, decimal> formula){
return e => new PriceItem {
Id = e.Id,
Price = formula(e)
};
}
so that I can call it like
prices.Select(GetPriceSelector(e => Math.Round(e.Price, 4)))
Unfortunately, EF complains about it:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities
How to rewrite the code to make EF happy?
First, the GetPriceSelector
method needs to take in an expression, not a function. The difference is that an expression is code as data so it can be translated to SQL, while a function is compiled code so it cannot be translated to SQL.
Next, you need a way to merge the two expressions. Doing this manually is hard. Fortunately, there is a library called LINQKit that can do that. Here is how you can solve your problem with 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)
}
来源:https://stackoverflow.com/questions/38766411/how-to-parameterize-a-selector-with-a-function-in-ef-query