これが可能かどうか、または探しているものを正しく表現しているかどうかはわかりませんが、ライブラリに次のコードが繰り返しあり、DRYを練習したいと思います。 Googleの単純なユーザー指定の検索フィールドに基づいてクエリを実行しているSQLServerテーブルのセットがあります。 LINQを使用して、検索文字列の内容に基づいて最終的なクエリを作成しています。ジェネリックスを使用し、ラムダ関数を渡して、これから再利用可能なルーチンを作成する方法を探しています。
string[] arrayOfQueryTerms = getsTheArray();
var somequery = from q in dataContext.MyTable
select q;
if (arrayOfQueryTerms.Length == 1)
{
somequery = somequery.Where<MyTableEntity>(
e => e.FieldName.StartsWith(arrayOfQueryTerms[0]));
}
else
{
foreach(string queryTerm in arrayOfQueryTerms)
{
if (!String.IsNullOrEmpty(queryTerm))
{
somequery = somequery
.Where<MyTableEntity>(
e => e.FieldName.Contains(queryTerm));
}
}
}
私は次のようなシグネチャを持つジェネリックメソッドを作成したいと思っていました。
private IQueryable<T> getQuery(
T MyTableEntity, string[] arrayOfQueryTerms, Func<T, bool> predicate)
すべてのテーブルで同じ検索戦略を使用しているため、使用法ごとに実際に異なるのは、MyTableとMyTableEntityの検索とFieldNameの検索だけです。これは意味がありますか? LINQを使用して、where句でクエリを実行するフィールドの名前を動的に渡す方法はありますか?または、これを述語ラムダとして渡すことはできますか?
e => e.FieldName.Contains(queryTerm)
SQLでこれを行うには、おそらくもっと簡単な方法が100万通りあることを私は理解していますが、これのためにLINQファミリーのすべてを維持したいと思います。また、このような問題にはジェネリックスが便利だと思います。何か案は?
基本的に条件付き述語ビルダーが必要なようです。
これをあなたが探しているものに形作ることができることを願っています、頑張ってください!
式ツリーを確認することをお勧めします。
IQueryable<T> getQuery<T>(T myTableEntity, string[] arrayOfQueryTerms, Expression<Func<T, bool>> predicate)
{ var fieldOrProperty = getMemberInfo(predicate);
/* ... */
}
MemberInfo getmemberInfo<T>(Expression<Func<T,bool> expr)
{ var memberExpr = expr as MemberExpression;
if (memberExpr != null) return memberExpr.Member;
throw new ArgumentException();
}
var q = getQuery<FooTable>(foo, new[]{"Bar","Baz"}, x=>x.FieldName);
私は最近これと同じことをしなければなりませんでした。 Dynamic Linqhere は、これを強く型付けしたままにする方法です。