2013-05-16 6 views
9

私はこのコードが動作することに驚きました。ラムダ式と|| Entity Frameworkの中にオペレータ

string category = null; 
Category Category = null; 
int categoryId = 0; 

var products = repository.Products 
    .Where(p => category == null || p.CategoryID == categoryId) 
    .ToList(); 

まだ次のコードは、を失敗:

string category = null; 
Category Category = null; 
int categoryId = 0; 

var products = repository.Products 
    .Where(p => category == null || p.CategoryID == Category.CategoryID) 
    .ToList(); 

私は問題は、私が使用しているにもかかわらず、ということを知っています| |私が思うようにはうまくいきません。

第2の例では、カテゴリ値がnullであっても、なぜカテゴリが参照されるのですか。短絡しないでしょうか?

+1

どのように失敗しますか? – MikeTheLiar

+1

'category'と' Category'を混在させているようですね? – itsme86

+2

'短絡しないでしょうか? 'これはクエリプロバイダによって実行されています。 C#コードをまったく実行していないので、C# '||'演算子のセマンティクスは適用されません。 – Servy

答えて

16

「OR」がSQLとしてデータベースに送信されています。エンティティフレームワークCategoryと評価すると、データベースに送信される適切なSQLが構築されます。最初の例では、同じ問題をEntity Frameworkに与えていませんでした。短絡の問題ではなく、(ORを含む)を適切なクエリに変換することです。

Linq-to-Objectsのメモリ内でクエリが発生していた場合(例として)、短絡してヌル間接参照を避けることが正しいと期待されます。そうではありません。式全体がSQLに変換されています。つまり、CategoryIDを取得するために、(nullに初期化された)Categoryを評価する必要があり、問題が発生します。

+1

私は、EntityフレームワークがCategory == nullを参照すると考えると、実際にCategoryオブジェクトを気にすることなくSQL文を構築できるようになります。なぜ私は最初にデータベースに送られなければならないのだろうかと思います。 –

+1

@ek_nyクエリープロバイダは、理論的には、それを行うために書かれている可能性があります。これは単純ではありませんでした。もしクエリープロバイダがそれを望んでいれば、 '||'演算子の最初のオペランドを定数値に評価しようと試みることができ、そうであれば第2オペランドを無視します。彼らはそうする時間を取らないことを選択したように見えるでしょう。 – Servy

+1

@ek_nyおそらくEFは、ブーリアン式が常にtrueとなり、最終的なSQLがレンダリングされるときにブール式がエリートされると判断しますが、その最適化は*最初に指定された式のオペランドを評価する*理にかなっている? –

関連する問題