2

我有我傳遞給IQueryable<>.Select()方式的投影功能:如何使用EF查詢中的函數參數化選擇器?

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是不支持 實體

如何重寫代碼,使EF幸福嗎?

回答

2

首先,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) 
} 
相關問題