2011-10-26 5 views
6

IQueryable<T>whereフィルタが適用されているかどうかを検出するにはどうすればよいですか?このコードでIterableに適用される場所を検出する<T>

、私はqueryFilteredwhereが適用されており、queryんではない

IQueryable<Customer> query = Context.Customers; 
IQueryable<Customer> queryFiltered = Context.Customers 
              .Where(c=>c.Name.Contains("ABC")); 
+1

なぜですか?より多くの文脈を与えるとより良い答えが得られるかもしれません –

答えて

9

あなたはIQueryable<T>実装にExpression propertyから返されExpressionを解析する必要があること、プログラムで知っておく必要があります。

Expressionツリーをクロールすると、Queryable.Where methodが呼び出されるようにクエリする必要があります。

Queryable.Wherewhereフィルタを検出するための最も一般的な方法になるだろうされている間、クエリ構文は、(using directivesで使用されているどのような名前空間に応じて)を使用する他の実装を可能にすることに注意してください。 Queryable.Where拡張メソッドを使用していないものがある場合は、それを明示的に検索する必要があります(Whereメソッドのフィルタリングの一般的な方法を使用してIQueryable<T>を返し、IQueryable<T>を返します)。 Expressionツリーをクロールする非常に簡単な方法を提供します(pointed out by xanatosとして)

ExpressionVisitor classは、私は非常にあなたのExpressionツリーを処理するためのベースとしてそのアプローチを使用することをお勧めします。

ExpressionVisitorクラスの実装は、クラスレベルでの状態の保存と公開に必要です。そのため、アクションを一度実行してから毎回ExpressionVisitorの新しいインスタンスを作成するパブリックメソッドを持つ内部クラスを作成することが最適です(IMO)。これは突然変異状態を扱うのに役立ち、正しく実行されると、メソッドがスレッドセーフであることが可能になります(それがあなたの懸念事項である場合)。

3

あなたがC#4.0を使用している場合は、このサンプルコードを使用することができます:それはExpressionVisitorに基づいていますGet all 'where' calls using ExpressionVisitor

を。それは、の部分を見つけるために、IQueryable<T>のさまざまな要素を「訪問」します。それは十分に単純なようです。

var wf = new WhereFinder(); 
var wheres = wf.GetWhere(query.Expression); 

if (wheres.Any()) 
{ 
    // There are Where in the query! 
} 

を使用すると、C#の= 3.5である場合は、コードを使用するにはMSDNのHow to: Implement an Expression Tree Visitor PLUS前のリンクからWhereFinderからExpressionVisitorサンプル(彼らはちょうどテストし、一緒に正しく動作)

を使用することができます

あなたが(正確に)同じくらい被害妄想Rune FSとして、WereFinder.VisitMethodCallにしている場合は、if

if (expression.Method.Name == "Where" && expression.Method.DeclaringType.FullName == "System.Linq.Queryable") 
を変更
+0

基本的には、どこに呼び出された別の非フィルタリングメソッドによって簡単にだまされる "どこ"と呼ばれるメソッドを検索しますか? –

+0

@RuneFSが修正されました。しかし、私は元のQ/Aに訂正を投稿するべきだと考えています:-) – xanatos

+0

元の投稿は、式ツリーが2つのwhere句を式として抽出することを前提にしています。 –

1

最も簡単な方法はq.Expression.ToString().Contains(".Where(")です。ご覧のとおり、はfalseを返し、queryFiltered.Expression.ToString().Contains(".Where(")はtrueを返します。

「フィルタリング」として他の式を数える場合は、それよりも複雑にする必要がありますが、式の訪問者のアプローチでも同じです。

私はあなたにこれを与えてくれますが、はるかに単純です。

+0

'new int [] {} .AsQueryable()。(p =>" .Where( "))ToString()。Contains(" Where( ")' :-) – xanatos

+0

@ xanatos ) –

+0

@xanatos ExpressionVisitorアプローチのオーバーロードでも同じことができます。どこが選択されているように正確に動作するかは、実際にあなたが投げているところでフィルタリングしていたようです。 –

関連する問題