2

(これは、SQL Serverが計算を行うことがあります):私は(動的に許可するのFunc変数または変数のいくつかの他の種類から、私のselect文の一部を作成したいと思う何EF + LINQ:Select文の一部を定義するために変数(多分Func変数)を定義して利用するにはどうすればよいですか?変数を使用する前

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

この):

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) 'メソッドであり、このメソッドをストア式に変換することはできません。

Select文の一部を定義するために変数(多分Func変数)を定義して利用するにはどうすればよいですか?

+0

あなたがのFuncを使用することはできません、それはSQL層に渡すことはできません。 – Gusman

+1

埋め込みに使用できるライブラリ[LinqKit](http://www.albahari.com/nutshell/linqkit.aspx)[この回答を見る](https://stackoverflow.com/q/42067722/5951133) 'Expression >' 'IQueryable' –

答えて

0

これは私が前に横たわって、私にとってうまくいく解決策を見つけたという完全に有効な質問です。

Func<MyEntity, decimal>の問題は、それが代理人であり、O/Rマッパーが内部式(あなたのケースでは2つのプロパティの乗算)にアクセスできることです。しかし、この情報はデリゲートに集められ、永遠に隠されています。

しかし、Expression<Func<MyEntity, decimal>> customCalculationで始めると、内部ロジックが式ツリーとして存在するため、より有望なものになります。 これは、式を呼び出せないという問題です。 customCalculation(m)はコンパイルされません。

コンパイラは

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

を書いてみましょうが、これはほとんどのO/Rマッパーによって理解されません。

しかし、少なくとも何らかの形でにはcustomCalculationラムダ式が含まれています。また、それが周囲の表現にどのように関係しているかがわかります。

いくつかの表現操作を含む元の作業バージョンのように、ここから式ツリーへの行き方:

我々はCompile() DになることですラムダのcustomCalculation.Compile()(m)を交換する必要がありますが、ラムダさんと代理人呼び出しのそれぞれの式で置き換えられたパラメータ。 customCalculationx => x.Column1 * x.Column2たのであれば、customCalculation.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) 
}); 

クエリの一部として選択を実行しようとしています。マッピング計算には通常の関数を使用してください。ラムダ関数はLINQで便利ですが、この場合は必要ありません。

+2

ヒント:この状況では' ToList() 'の代わりに' AsEnumerable() 'を使います。あなたはリストを必要としません、あなたは、単にIEnumerableバージョンの 'Select'をオーバーロード解決するようにコンパイラを欺くことを望みます。また、私の質問は、MyCalculation式を '.Select'セレクタに渡してEFでSQLに変換する方法に関するものだと思います。 – tinudu

関連する問題