2014-01-11 2 views
0

일치하는 항목을 확인하려는 모델의 각 문자열 필드에 대해이 메서드가 중복되지 않도록 할 수 있습니까? MyModel이 추상화 된 경우 람다 식의 MyModelField이 더 이상 인식되지 않으므로 이름을 사용하여 필드에 액세스 할 수 있다고 생각하고 있습니까?표현 추상화

private Expression<Func<MyModel, bool>> MatchMyModelFieldByStrategy(SearchItem searchItem) 
{ 
    var searchItemKey = searchItem.Value.ToLower(); 
    Expression<Func<MyModel, bool>> defaultExp = s => s.MyModelField.ToLower().Contains(searchItemKey); 
    switch (searchItem.SearchStrategy) 
    { 
     case StrStrategy.Contains: 
      return defaultExp; 
     case StrStrategy.StartsWith: 
      return s => s.MyModelField.ToLower().StartsWith(searchItemKey); 
     case StrStrategy.EndsWith: 
      return s => s.MyModelField.ToLower().EndsWith(searchItemKey); 
     case StrStrategy.Equals: 
      return s => s.MyModelField.ToLower().Equals(searchItemKey); 
    } 
    return defaultStrat; 
} 

내가 동적 엔티티 프레임 워크 쿼리에 사용할 조건을 구축하는 방법을 호출 할 필요가

편집 할 수 있습니다.

+1

는 상부 케이스 문자열 검색 및 .NET의 비교에 적합하다. – Ivan

+1

Entity Framework 또는 LINQ2SQL에서 'MatchMyModelFieldByStrategy'의 결과를 사용할 계획입니까? 그렇다면 배치 된 응답의 코드로 인해 실행시 엔티티 명령 컴파일 예외가 발생하게됩니다. 이는 기본 LINQ 공급자가'selector '를 인식하지 못하기 때문입니다. – Dennis

+0

@Dennis yep 동적 쿼리 빌더를 만들기 위해 필요합니다 ... EF와 함께 사용할 유효한 대안을 알고 있습니까? –

답변

1

의 결과를 사용하려는 경우에서 Entity Framework 또는 LINQ2SQL을 사용하는 경우 selector은 기본 LINQ 공급자가 엔터티 명령 텍스트를 작성하는 동안 대리자를 인식하지 않으므로 대리자 대신 표현식이어야합니다.

따라서, 당신은 다음과 같이 표현 스스로 뭔가를 구축해야 :

비슷한 유형 :

enum SearchStrategy 
{ 
    Contains, 
    StartsWith, 
    EndsWith, 
    Equals 
} 

class SearchItem 
{ 
    public SearchStrategy SearchStrategy { get; set; } 
    public string Value { get; set; } 
} 

다음은 필터링 표현식을 빌드 코드가있어 가지고, 가정

(:

static class QueryBuilder 
{ 
    private static readonly Lazy<MethodInfo> toLowerMethodInfo; 
    private static readonly Dictionary<SearchStrategy, Lazy<MethodInfo>> searchStrategyToMethodInfoMap; 

    static QueryBuilder() 
    { 
     toLowerMethodInfo = new Lazy<MethodInfo>(() => typeof(string).GetMethod("ToLower", new Type[0])); 

     searchStrategyToMethodInfoMap = new Dictionary<SearchStrategy, Lazy<MethodInfo>> 
     { 
      { 
       SearchStrategy.Contains, 
       new Lazy<MethodInfo>(() => typeof(string).GetMethod("Contains", new[] { typeof(string) })) 
      }, 
      { 
       SearchStrategy.StartsWith, 
       new Lazy<MethodInfo>(() => typeof(string).GetMethod("StartsWith", new[] { typeof(string) })) 
      }, 
      { 
       SearchStrategy.EndsWith, 
       new Lazy<MethodInfo>(() => typeof(string).GetMethod("EndsWith", new[] { typeof(string) })) 
      }, 
      { 
       SearchStrategy.Equals, 
       new Lazy<MethodInfo>(() => typeof(string).GetMethod("Equals", new[] { typeof(string) })) 
      }, 
     }; 
    } 

    public static Expression<Func<T, bool>> MatchMyModelFieldByStrategy<T>(SearchItem searchItem, Expression<Func<T, string>> selector) 
    { 
     // "doe" 
     var searchItemKey = searchItem.Value.ToLower(); 
     // _.Name.ToLower() 
     var toLowerCallExpr = Expression.Call(selector.Body, toLowerMethodInfo.Value); 
     // a method we shall use for searching 
     var searchMethodInfo = searchStrategyToMethodInfoMap[searchItem.SearchStrategy].Value; 

     // _ => _.Name.ToLower().SomeSearchMethod("doe") 
     return Expression.Lambda<Func<T, bool>>(
      Expression.Call(toLowerCallExpr, searchMethodInfo, Expression.Constant(searchItemKey)), 
      selector.Parameters); 
    } 
} 

모든 MatchMyModelFieldByStrategy 전화에 대해 동일한 결과를 얻을 수 있기 때문에 반영 결과를 캐시하는 데 약간의 게으름을 추가했습니다.

지금 테스트 개체 유형 :

class MyEntity 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

...와 샘플 코드 : 그런데

static void Main(string[] args) 
    { 
     Console.WriteLine(QueryBuilder.MatchMyModelFieldByStrategy<MyEntity>(
      new SearchItem { SearchStrategy = SearchStrategy.Contains, Value = "doe" }, _ => _.Name)); 
     Console.WriteLine(QueryBuilder.MatchMyModelFieldByStrategy<MyEntity>(
      new SearchItem { SearchStrategy = SearchStrategy.StartsWith, Value = "doe" }, _ => _.Name)); 
     Console.WriteLine(QueryBuilder.MatchMyModelFieldByStrategy<MyEntity>(
      new SearchItem { SearchStrategy = SearchStrategy.EndsWith, Value = "doe" }, _ => _.Name)); 
     Console.WriteLine(QueryBuilder.MatchMyModelFieldByStrategy<MyEntity>(
      new SearchItem { SearchStrategy = SearchStrategy.Equals, Value = "doe" }, _ => _.Name)); 

     Console.ReadLine(); 
    } 
+0

과 함께 사용하지 않을 경우 정답. 매우 상세한 답변으로, @Dennis에게 감사드립니다. –

1

매개 변수로 속성 선택기 함수를 제공 할 수 있습니다. 예를 들어 :

private Expression<Func<MyModel, bool>> MatchMyModelFieldByStrategy(SearchItem searchItem, Func<MyModel, string> propertySelector) 
{ 
    var searchItemKey = searchItem.Value.ToLower(); 
    Expression<Func<MyModel, bool>> defaultExp = s => propertySelector.Invoke(s).ToLower().Contains(searchItemKey); 
    switch (searchItem.SearchStrategy) 
    { 
     case StrStrategy.Contains: 
      return defaultExp; 
     case StrStrategy.StartsWith: 
      return s => propertySelector.Invoke(s).ToLower().StartsWith(searchItemKey); 
     case StrStrategy.EndsWith: 
      return s => propertySelector.Invoke(s).ToLower().EndsWith(searchItemKey); 
     case StrStrategy.Equals: 
      return s => propertySelector.Invoke(s).ToLower().Equals(searchItemKey); 
    } 
    return defaultStrat; 
} 

과 같이 사용할 수있는 :

private Expression<Func<MyModel, bool>> MatchMyModelFieldByStrategy(SearchItem searchItem, Func<MyModel, String> selector) 
{ 
    var searchItemKey = searchItem.Value.ToLower(); 
    Expression<Func<MyModel, bool>> defaultExp = s => selector(s).ToLower().Contains(searchItemKey); 
    switch (searchItem.SearchStrategy) 
    { 
     case StrStrategy.Contains: 
      return defaultExp; 
     case StrStrategy.StartsWith: 
      return s => selector(s).ToLower().StartsWith(searchItemKey); 
     case StrStrategy.EndsWith: 
      return s => selector(s).ToLower().EndsWith(searchItemKey); 
     case StrStrategy.Equals: 
      return s => selector(s).ToLower().Equals(searchItemKey); 
    } 
    return defaultStrat; 
} 

를 그리고 이런 식으로 사용합니다 :

var matchExpression = MatchMyModelFieldByStrategy(someSearchItem, model => model.MyModelField); 
+0

위와 같이 EF –

1

당신은 타겟 필드 선택기를 정의 할 수 있습니다

MatchMyModelFieldByStrategy(searchItem, x=>x.MyModelField); 
+0

과 함께 사용하지 않는 경우 올바른지, EF –