2017-04-11 3 views
3

を拡張:LINQのは、私は次のシグネチャがありServiceStack.OrmLite.SqlExpressionVisitorための一般的なワイルドカード検索を書くことをしようとしている表現

EVは、フィルタの残りの部分で、フィールドがためにゲッターである
public static SqlExpressionVisitor<T> WhereWildcardSearch<T> (this SqlExpressionVisitor<T> ev, Expression<Func<T,string>> field, string search) 

検索するフィールドと検索するフィールドは入力された用語です。

通常(非ジェネリック)私は以下のように記述します。

if(search.StartsWith('*') && search.EndsWith('*')) 
    ev = ev.Where(x => x.foo.Contains(search.Trim('*'))); 

そしてもちろんのもx.foo.StartsWithまたはEndsWithのための変種。

は今、私は、これはLinq2Sqlを使用してSQLに変換する必要があるとして、私は、直接表現をコンパイルして呼び出すことはできません擬似コード:)もちろん

ev = ev.Where(x => field(x).Contains(search.Trim('*'))); 

(のようなものを探しています。

これは、これまでの私のコードです:

var getFieldExpression = Expression.Invoke (field, Expression.Parameter (typeof (T), "getFieldParam")); 
var searchConstant = Expression.Constant (search.Trim('*')); 

var inExp = Expression.Call (getFieldExpression, typeof(String).GetMethod("Contains"), searchConstant); 
var param = Expression.Parameter (typeof (T), "object"); 
var exp = Expression.Lambda<Func<T, bool>> (inExp, param); 

ev = ev.Where (exp); 

私が直接$"LIKE %search%"か何かでSQLを記述する必要があることを教えないでください - 私は他の方法があることを知っているが、これを解決することは私の理解を助けます私はそれを解決することができないとき、私は一般的にLinqとExpressionsのそれをバグします。ここで

答えて

3

が、それは(私はそれはあなたが間違って何をしたかくらいの補足説明せずに、あなたのために明らかになると思いますが、そうでない場合は - 明確化を要求して自由に感じる)に行うことができる方法である。

// extract property name from passed expression 
var propertyName = ((MemberExpression)field.Body).Member.Name;    
var param = Expression.Parameter(typeof(T), "object");    
var searchConstant = Expression.Constant(search.Trim('*')); 
var contains = typeof(String).GetMethod("Contains"); 
// object.FieldName.Contains(searchConstant) 
var inExp = Expression.Call(Expression.PropertyOrField(param, propertyName), contains, searchConstant);    
// object => object.FieldName.Contains(searchConstant) 
var exp = Expression.Lambda<Func<T, bool>>(inExp, param); 

受けてコメントします。あなたは2つの表現木を持っています:1つはあなたに渡されており、もう1つは構築中のものです(exp)。この単純なケースでは、両方とも同じ数のパラメータを使用し、それらのパラメータは同じタイプです(T)。この場合、あなたはこのように、field式ツリーからパラメータを再利用することができます

// use the same parameter 
var param = field.Parameters[0]; 
var searchConstant = Expression.Constant(search.Trim('*')); 
var contains = typeof(String).GetMethod("Contains");    
// note field.Body here. Your `field` expression is "parameter => parameter.Something" 
// but we need just "parameter.Something" expression here 
var inExp = Expression.Call(field.Body, contains, searchConstant); 
// pass the same parameter to new tree 
var exp = Expression.Lambda<Func<T, bool>>(inExp, param); 

をより複雑なケースでは、別の(最終)式ツリーからパラメータを参照するために、1式ツリーのパラメータを置き換えるためにExpressionVisitorを使用する必要があります。

+0

これは完璧な動作をしており、まさに私が求めていたものです。ありがとう! ちょっと質問があります:フィールドゲッター式が渡されたとき(これは私が尋ねたように)動作するだけです。任意の式>で動作する簡単な修正はありますか? (与えられた式がlinq2sqlで有効であると仮定して) – KillPinguin

+1

@KillPinguinこの点を明確にするために答えを更新しました – Evk

+0

は今理解しています。ありがとうございました! – KillPinguin

関連する問題