2012-01-23 2 views
9

私はMicrosoftのEntity FrameworkをORMとして使用していますが、次の問題を解決する方法が不思議です。 今日Product.StartDateが今日よりも大きいProductsコレクションから多数のProductオブジェクトを取得します。 (これは、問題全体の簡易版です。)EntityFrameworkのLINQパーサーが外部定義された述語を異なる方法で処理するのはなぜですか?

私は現在使用します。

var query = dbContext.Products.Where(p => p.StartDate > DateTime.Now); 

これを実行すると、クエリに例えばToList()を使用した後、それが動作して作成されたSQLが効果的である:

SELECT * FROM Product WHERE StartDate > (GetDate()); 

しかし、私はより良い保守のための関数に述語を移動したいので、私はこの試みた:

private Func<Product, bool> GetFilter() 
{ 
    Func<Product, bool> filter = p => p.StartDate > DateTime.Now; 
    return filter; 
} 
var query = dbContext.Products.Where(GetFilter()); 

これもそれは同じProductセットを返しますが、SQLを作成し、この時間が類似している限り、ビューのコードポイントから動作します:

SELECT * FROM Product; 

フィルタは、それを行っているクライアントへのSQL Serverから移動されますはるかに効率が悪い。

だから私の質問は以下のとおりです。

  • ですが、なぜでしょう、なぜLINQパーサはとても異なっこれら二つのフォーマットを処理するのでしょうか?
  • フィルタを別にしても、サーバー上で実行させることを利用するにはどうすればよいですか?

答えて

4

Funcが返されますが、SQLに述語を挿入するには、LINQに式ツリーが必要です。メソッドの戻り値の型(もちろんローカル変数)をExpression<Func<Product, bool>>に変更するとうまくいくはずです。

8

あなたが意図したように機能するには、Expression<Func<Product, bool>>を使用する必要があります。 Func<Product, bool>は、LINQに、プログラムでMSILにWhereを実行し、SQLでは実行しないように指示します。だからこそ、SQLがテーブル全体を引っ張っているのですから、.NETコードはテーブル全体で述語を実行しています。

+0

+1ちょうど私にそれを打つ。 –

+0

@Dommer haha​​!私は通常、非常に良い "クイックドロー"ではありません! –

+1

ありがとうございました。 –

2

2番目のケースでは、filter funcが任意である可能性があるため、LINQ to EFはSQLへのフィルタ処理を解析できず、クライアント側で解決する必要があります。

+0

合意されましたが、最初の例の式が何かになる可能性があるので、それはすべての答えになることはできません。インライン述語と同じ時間にGetFilter関数を調べた場合、問題はありません。これは実行の順序が異なることを意味しますか? –

関連する問題