次の列と対応するエンティティを持つ単一のテーブル (Car と呼ばれる) がある場合を考えてみましょう。
string Make
string Model
string Owner
ここで、検索の対象となるプロパティを (チェックボックスを使用して) ユーザーが選択できる検索を作成したいと考えています。複数を選択した場合、検索文字列がそれらの少なくとも 1 つに含まれていれば十分です。
さらに、(スペースで区切られた) 複数の検索文字列が指定された場合、検索はすべての単語が見つかった場合にのみ一致する必要があります (たとえば、検索文字列が「ter mist」の場合、所有者が「mister」の車が一致します)。
Expression<Func<Car, bool>>
いくつかの調査を行った後、選択したプロパティごとに のリストを作成し、検索文字列の単語ごとに 1 つ追加してから、これらすべてをまとめて 1 つのExpression<Func<Car, bool>>
. 選択したすべてのプロパティに対してこれらを取得したら、それらをまとめて、最終的なフィルターを作成します。しかし、これは私が苦労しているところです。
結局、私が得た最も遠いものは、NotSupportedException ということでしたThe LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
結合を行うためのヘルパー関数を次に示します ( http://social.msdn.microsoft.com/Forums/en-US/linqprojectgeneral/thread/60a1f4c0-d4d9-4143-91aa-79d29dde7a7c/から見つかりました):
public static Expression<Func<T, bool>> Or<T>(params Expression<Func<T, bool>>[] predicates)
{
if (predicates.Length == 1)
return predicates[0];
Expression<Func<T, bool>> result = predicates[0];
for (int i = 1; i < predicates.Length; i++)
{
result = OrTwo(result, predicates[i]);
}
return result;
}
private static Expression<Func<T, bool>> OrTwo<T>(Expression<Func<T, Boolean>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return (Expression.Lambda<Func<T, Boolean>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters));
}
これも驚くほどややこしくなってきているので、もっと簡単な方法があるに違いないと思い始めています。では、これを解決する最も簡単な方法は何でしょうか?
解決
いくつかのことを試した後 (LINQKit、Albahari の PredicateBuilder、自分で式ツリーをいじる)、最終的にここにたどり着きました。PredicateBuilder のこのユニバーサル バージョンは、他の外部依存関係なしで動作し、EF と完全に互換性があります。それは問題を解決することを本当に簡単にしました。