2017-04-11 9 views
3

나는 다음과 같은 서명이있는 ServiceStack.OrmLite.SqlExpressionVisitor에 대한 일반적인 와일드 카드 검색을 쓰기 위해 노력하고있어를 연장 :는 Linq에 표현

public static SqlExpressionVisitor<T> WhereWildcardSearch<T> (this SqlExpressionVisitor<T> ev, Expression<Func<T,string>> field, string search) 
EV 필터의 나머지 부분입니다

, 필드의 게터입니다 검색 할 필드와 입력 한 검색어가 검색됩니다. 나는 다음을 작성합니다 (제네릭이 아닌)

일반적으로는 :

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); 

의견을 남기다. 당신은 두 개의 수목이 있습니다. 하나는 당신에게 건네지는 것이고 다른 하나는 건립하는 것입니다 (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); 

을 더 복잡한 경우에는 다른 (최종) 식 트리에서 매개 변수를 참조하는 하나의 식 트리에서 매개 변수를 대체 할 ExpressionVisitor을 사용해야 할 수 있습니다 .

+0

이것은 완벽하게 작동하며, 내가 정확히 요구 한 것입니다. 감사! 추가 질문 : 필드 물음표 표현식이 전달 될 때만 작동합니다 (물어 보는 것처럼). Expression >에서 쉽게 작동하는 수정이 있습니까? (주어진 표현식이 linq2sql에서 유효하다고 가정) – KillPinguin

+1

@KillPinguin이 점을 명확히하기 위해 답변을 업데이트했습니다. – Evk

+0

지금 이해했습니다. 고맙습니다! – KillPinguin