2

嘗試使用一個變量之前(這有SQL Server做計算):EF + LINQ:我如何定義和使用一個變量(也許是一個Func變量)來定義Select語句的一部分?

IQueryable<MyEntity> query = _dbSet; // IQueryable<TEntity> 
var results = query.Select(m => new MyViewModel 
{ 
    MyCalculation = m.Column1 * m.Column2 
}).ToList(); 

我想要做的(動態創建我從函數求變量或一些其他類型的變量的select語句的一部分,允許什麼此):

IQueryable<MyEntity> query = _dbSet; // IQueryable<TEntity> 
Func<MyEntity, decimal> funcVariableAttempt = m => m.Column1 * m.Column2; 
var results = query.Select(m => new MyViewModel 
{ 
    MyCalculation = funcVariableAttempt.Invoke(m) // My foolish attempt does not work. 
}).ToList(); 

我得到的錯誤,當我嘗試了我想要的(又名我愚蠢的嘗試):

LINQ到實體無法識別方法「System.Decimal INVO ke(MyProject.Repository.Models.MyEntity)'方法,並且此方法不能轉換爲商店表達式。

如何定義和利用一個變量(也許是一個Func變量)來定義Select語句的一部分?

+0

你不能使用函數功能,它不能被傳遞到SQL層。 – Gusman

+1

請參閱[本答案](https://stackoverflow.com/q/42067722/5951133)和一個可用於嵌入的庫[LinqKit](http://www.albahari.com/nutshell/linqkit.aspx) '表達式>在'IQueryable'中'' –

回答

0

這是一個完全有效的問題,我早先就對其進行了標記,並找到了適合我的解決方案。

Func<MyEntity, decimal>的問題在於它是一個委託,並且O/R映射器必須能夠訪問內部表達式(在您的案例中乘以兩個屬性)。但是這些信息被編入代表並永久隱藏。

如果你從Expression<Func<MyEntity, decimal>> customCalculation開始,事情看起來更有希望,因爲你有內部邏輯作爲表達式樹。 問題在於:您無法調用表達式。 customCalculation(m)不能編譯。

,編譯器將讓你寫

m => new MyViewModel { MyCalculation = customCalculation.Compile()(m) } 

,但這並不被大多數O/R映射器可以理解。

但是你發現它至少在某種程度上包含customCalculation lambda表達式以及它與其周圍表達式的關係。

充分利用這裏的表達式樹在你原來的工作方案包括一些表達操作:

我們與身體是要Compile() d拉姆達的更換customCalculation.Compile()(m),但與拉姆達的將參數替換爲委託調用的相應表達式。所以,如果customCalculationx => x.Column1 * x.Column2customCalculation.Compile()(m)必須與m.Column1 * m.Column2

這樣做替代是不平凡的,因爲拉姆達本身挖出來現場的編譯器生成的封閉類的實例裏面。

我已經發布了這個表達式操縱器in another similar question的實現。希望有所幫助。

有了這一點,你應該能夠:

var customCalculation = (Expression<Func<MyEntity, decimal>>)(x => x.Column1 * x.Column2); 
var selector = Express.Prepare((Expression<Func<MyEntity, MyViewModel>>)(m => new MyViewModel { MyCalculation = customCalculation.Compile()(m) })); 
var result = query.Select(selector).ToList(); 
+0

fyi:我認爲這是迄今爲止最好的答案!非常感謝。你實際上在我這裏困惑了一下,但是,結合你對類似問題的聯繫,我能夠實現我的目標!再次感謝! –

+0

很高興我能幫到你。我承認在解釋事情上做得不好。編輯答案,希望使其更容易理解。 – tinudu

0

正如您所知道的,您的funcVariableAttempt對您的數據庫沒有意義,因此您必須在linq-to-object上下文中調用您的方法。即例如首先獲取的數據作爲Enumerable,然後調用你的方法:

var results = query.Select(m => new { 
Column1= col1, 
Column2= col2 
}).AsEnumerable() 
    .Select(m => new MyViewModel 
{ 
    MyCalculation = Foo(m.Column1, m.Column2) 
}); 

*注:代碼沒有進行測試。

0

您應該首先調用ToList()並對內存中的結果執行Select()。

var results = query.ToList() 
.Select(m => new MyViewModel { 
    MyCalculation = Foo(m.Column1, m.Column2) 
}); 

您試圖執行選擇作爲查詢的一部分。您應該使用常規函數進行映射計算。 Lambda函數對LINQ很有用,但在這種情況下,它們不是必需的。

+2

提示:在這種情況下使用'AsEnumerable()'而不是'ToList()'。你不想要一個列表,你只想誘使編譯器重載 - 解決IEnumerable版本的Select。另外我想問的是如何讓MyCalculation表達式進入'.Select'選擇器以被EF轉換爲SQL。 – tinudu

相關問題