2010-12-30 8 views
8

私はSQLの動作に奇妙なLINQを見つけました。LINQ to SQL:ラムダ式を再利用

ラムダ式を定義し、それをLINQステートメントで使用したいと考えています。 、

Unsupported overload used for query operator 'Any'. 

しかし:

[...] 
Func<Table1, bool> lambda = x => x.Id > 1000; 
var result = dataContext.Table1s.Where(lambda); 
[...] 

をしかし、私は関連するテーブル

[...] 
Func<Table1, bool> lambda = x => x.Id > 1000; 
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda)); 
[...] 

に声明の中で、私のラムダ式を使用しようとすると、私は例外を取得:次のコードは正常に動作しますこれは私には分かりません:ラムダをクエリに直接入れるとうまくいく:

[...] 
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000)); 
[...] 

なぜですか?

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

+0

'var lamda = x => x.Id> 1000;'を試してみてください。それが助けになるかどうかわからないが、それは... – Alxandr

+0

@Alxandr - それは実際に法的ではない。ラムダ式は 'Func <>'か 'Expression >'にコンパイルできます。あなたの例では、コンパイラはどちらを使いたいのかを知ることができず、エラーを投げます。 –

答えて

18

これは取引です:dataContext.Table1sIQueryable<T>です。 IQueryable<T>は、タイプExpression<Func<T, bool>>の述語を取るWhereAnyメソッドを定義します。 Expression<>ラッパーは、LINQ to SQLがラムダ式をSQLに変換してデータベースサーバー上で実行できるようにするために重要です。

しかし、IQueryable<T>は、IEnumerable<T>も含みます。 IEnumerable<T>WhereAnyメソッドも定義しますが、IEnumerableバージョンはFunc<T, bool>という述語を取ります。これはコンパイルされた関数であり式ではないため、SQLに変換することはできません。その結果、このコードは...

Func<Table1, bool> lambda = x => x.Id > 1000; 
var result = dataContext.Table1s.Where(lambda); 

...メモリにTable1sのうち、すべてのレコードを引っ張ってくるし、次にメモリ内のレコードをフィルタします。それはうまくいきますが、あなたのテーブルが大きければ本当に悪いニュースです。

Func<Table1, bool> lambda = x => x.Id > 1000; 
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda)); 

このバージョンには2つのラムダ式があります。第2のものは、Whereに直接渡され、Expressionであり、Funcへの参照を含む。この2つを混在させることはできません。エラーメッセージは、Anyへの呼び出しにはExpressionが必要ですが、Funcに渡していることを伝えています。このバージョンで

var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000)); 

それはあなたのコードは、SQLにLINQでSQLに変換されるようにする場合の唯一の選択肢だから、あなたの内側のラムダは自動的にExpressionに変換されています。他のケースでは、ラムダをExpressionの代わりにFuncにする必要があります。この場合はそうではありません。

解決策は何ですか?実際にはかなり簡単です:

Expression<Func<Table1, bool>> lambda = x => x.Id > 1000; 
+1

+1本当に良い説明。 –

+0

ありがとうございます。コンパイラのエラーは次のとおりです。 引数2: 'System.Linq.Expressions.Expression >'を 'System.Func ' –

+1

に変換できません。このエラーメッセージは、 [IEnumerable](http://msdn.microsoft.com/en-us/library/bb534803.aspx)のバージョンでは、IEnumerableを実装しているがIQueryableは実装していないオブジェクトの 'Where'または' Any'を呼び出していますFunc、[IQueryable](http://msdn.microsoft.com/en-us/library/bb548547.aspx)バージョンの式が必要です。 Expressionを受け入れない場合、オブジェクトはIQueryableではない可能性があります。 –

0

Table1は同じ名前空間を指していますか?最初の例では、dataContextの直下にあるTable1オブジェクトを照会しています.2番目の例では、Table2オブジェクトのプロパティであるTable1オブジェクトに対して照会しています。最後の例では、匿名問題を解決する関数です。

私はTable2オブジェクトのプロパティですTable1オブジェクトの種類を検索し、dataContextに直接接続されているTable1オブジェクトと比較します。あなたのラムダ式は、dataContextに接続されているオブジェクトの型を使用していると私の推測では違います。