【问题标题】:How to parameterize a selector with a function in EF query?如何在 EF 查询中使用函数参数化选择器?
【发布时间】:2016-08-04 11:43:29
【问题描述】:

我有一个投影函数,我传递给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 不支持 LINQ 表达式节点类型“Invoke” 实体

如何重写代码让EF开心?

【问题讨论】:

    标签: c# entity-framework linq entity-framework-6 expression-trees


    【解决方案1】:

    首先,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)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-05
      • 1970-01-01
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      • 2013-11-14
      • 1970-01-01
      • 2020-05-22
      相关资源
      最近更新 更多