如何使用EF查询中的函数参数化选择器?

我有一个投影函数,我传递给IQueryable.Select()方法:

 private static Expression<Func> GetPriceSelector(){ return e => new PriceItem { Id = e.Id, Price = Math.Round(e.Price, 4) }; } 

一切正常,但我想像这样参数化:

 private static Expression<Func> GetPriceSelector(Func formula){ return e => new PriceItem { Id = e.Id, Price = formula(e) }; } 

所以我可以称之为

 prices.Select(GetPriceSelector(e => Math.Round(e.Price, 4))) 

不幸的是,EF抱怨它:

LINQ to Entities中不支持LINQ表达式节点类型“Invoke”

如何重写代码让EF快乐?

首先, GetPriceSelector方法需要接受表达式而不是函数。 不同之处在于表达式是代码作为数据,因此可以将其转换为SQL,而函数是编译代码,因此无法将其转换为SQL。

接下来,您需要一种方法来合并这两个表达式。 手动执行此操作很难。 幸运的是,有一个名为LINQKit的库可以做到这一点。 以下是使用LINQKit解决问题的方法:

 private static Expression> GetPriceSelector( Expression> formula) { Expression> 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) }