0

Queryablemyに述語があるかどうかを確認する方法が必要ですWhere

var queryA = db.Contacts.Where(x => x.IsAdministrator);

var hasPredicate = HasPredicate(queryA);
// return true

var queryB = db.Contacts;

var hasPredicateB = HasPredicate(queryB);
// return false

これが最善のアプローチではないことは承知しており、明らかに皆さんも同意しています。

手早く表面的に説明します。

別のコンテキストで一次調査として使用する QueryBase を呼び出すクエリを返すメソッドがあります。

現在のコンテキストでは、結合を作成するために QueryBase ID のリストが必要です。

いずれにせよ、これらの調査で使用されるオブジェクトは非常に大きく複雑であるため、QueryBase を「やり直す」必要はありません。この巨大なオブジェクトに基準がなく、クエリが「生」の場合。

オブジェクトが空かどうかを検証する必要があることはわかっていますが、それは実際には機能します。他の値によって異なるいくつかの異なるデフォルト値があり、これらすべての検証は QueryBase を返すメソッド内で行われるからです。

クエリが「空」の場合は、これをスキップする必要があります。

4

2 に答える 2

2

Linq の IQueryable 側は式で実行されます。式はオブジェクトベースのツリー構造であり、Queryable に対して実行できるすべての操作を多かれ少なかれ表しています。これにより、「データとしてのコード」が可能になり、コードが他のコードを動的に構築し、SQL などの何かを構築するための構造として評価したり、ランタイム内で結果を生成するためにコンパイルおよび実行したりできます。

特定のケースでは、この式ツリーを上から下、左から右にトラバースし、"System.Linq.Queryable.Where" という名前のメソッドを記述する MethodInfo を参照して、タイプのノードMethodCallExpression(または NodeType を持つノード) を探します。 ExpressionType.Call「2」。

さて、Jon Skeet と他の人が言ったように、これはもろいです。最初に、他のすべてのタイプの Expression ノードを適切にトラバースして、ツリー全体をトラバースして Where 句を見つけられるようにする Expression walker を実装する必要があります。次に、「トランク」IQueryable で動作しない Where メソッドが存在する可能性があります。たとえば、サブコレクションで動作するラムダステートメントにある場合があります。

db.Contacts
    .OrderBy(c=>c.PhoneNumbers
                    .Where(pn=>pn.Type == PhoneType.Mobile)
                    .OrderBy(pn=>pn.DateLastCalledSuccessfully)
                    .FirstOrDefault());

これはもう 1 つの落とし穴です。FirstOrDefault()(および) メソッドにはLastOrDefault()、述語を受け入れるオーバーロードがあります。これらは、必ずしも Queryable.Where 関数の呼び出しとして評価されるとは限りません。同様に、エンド ユーザーは独自の述語スタイルのメソッド ( 、 など) を定義しFilterBy()WhereNot()、自分で使用するか、アプリケーションでエンド ユーザーに表示するクエリ文法に一致させることができます。あなたのコードが検索するだけの場合System.Linq.Queryable.Where()(または "Where" という名前のメソッドを検索したとしても)、これらは見つかりません。同様に、検索範囲を広げるほど、述語に使用されると予想される名前に一致するメソッドが見つかりますが、それらは述語ベースの関数ではありません。

于 2013-07-30T21:32:46.680 に答える