2013-07-25 2 views
5

В MVC4 я предоставляю пользователю окно поиска для поиска любых значений в таблице. Так я реализую Generic Filter Condition на стороне сервера в C#Реализация фильтра LINQ с выражениями

Нужна помощь, чтобы объединить несколько выражений, чтобы сформировать единое выражение

Expression<Func<T, bool>> 

Для примера

Таблица Столбцы

MenuText, название роли (сопоставление ролей.), Actio nName

Теперь Если пользователь, введенный в поле поиска для ABC, который может быть в любой из строк в столбцах, указанных в столбцах, необходимо фильтровать.

Модель

public class Menu 
{ 
    public string MenuText {get;set;} 
    public Role Role {get;set;} 
    public string ActionName {get;set;} 
} 

public class Role 
{ 
    public string Name {get;set;} 
} 

До сих пор я реализовал

/// <summary> 
    /// string[] properties property.Name (MenuText, ActionName), including deeper Mapping names such as (Role.Name) 
    /// </summary> 
    public static Expression<Func<T, bool>> FilterKey<T>(string filterText, params string[] properties) 
    { 
     ParameterExpression parameter = Expression.Parameter(typeof (T)); 
     Expression[] propertyExpressions = properties.Select(
      x => !string.IsNullOrEmpty(x) ? GetDeepPropertyExpression(parameter, x) : null).ToArray(); 

     Expression<Func<T, bool>> predicate = PredicateBuilder.False<T>(); 
     foreach (Expression expression in propertyExpressions) 
     { 
      var toLower = Expression.Call(expression, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes)); 
      var like = Expression.Call(toLower, typeof(string).GetMethod("Contains"), Expression.Constant(filterText.ToLower())); 
      //TODO: Combine expressions to form single Expression<Func<T, bool>> expression 

     } 
     return predicate; 
    } 

     /// <summary> 
     /// To Get Deeper Properties such as Role.Name Expressions 
     /// </summary> 
     private static Expression GetDeepPropertyExpression(Expression initialInstance, string property) 
     { 
      Expression result = null; 
      foreach (string propertyName in property.Split('.')) 
      { 
       Expression instance = result ?? initialInstance; 
       result = Expression.Property(instance, propertyName); 
      } 
      return result; 
     } 
+0

Вы задали почти одинаковый вопрос 3 раза за последние 24 часа ... – leppie

ответ

0

Спасибо к NinjaNye, я заимствовал BuildOrExpression, который разрешил мою проблему

Вот решение

public static Expression<Func<T, bool>> FilterKey<T>(string filterText, params string[] properties) 
     { 
      ParameterExpression parameter = Expression.Parameter(typeof (T)); 
      Expression[] propertyExpressions = properties.Select(
       x => !string.IsNullOrEmpty(x) ? GetDeepPropertyExpression(parameter, x) : null).ToArray(); 

      Expression like= propertyExpressions.Select(expression => Expression.Call(expression, typeof (string).GetMethod("ToLower", Type.EmptyTypes))).Select(toLower => Expression.Call(toLower, typeof (string).GetMethod("Contains"), Expression.Constant(filterText.ToLower()))).Aggregate<MethodCallExpression, Expression>(null, (current, ex) => BuildOrExpression(current, ex)); 
      return Expression.Lambda<Func<T, bool>>(like, parameter); 
     } 

     private static Expression BuildOrExpression(Expression existingExpression, Expression expressionToAdd) 
     { 
      if (existingExpression == null) 
      { 
       return expressionToAdd; 
      } 

      //Build 'OR' expression for each property 
      return Expression.OrElse(existingExpression, expressionToAdd); 
     } 


     private static Expression GetDeepPropertyExpression(Expression initialInstance, string property) 
     { 
      Expression result = null; 
      foreach (string propertyName in property.Split('.')) 
      { 
       Expression instance = result ?? initialInstance; 
       result = Expression.Property(instance, propertyName); 
      } 
      return result; 
     } 
6

Я создал несколько поиска IQueryable методы расширения, которые вы должны быть в состоянии использовать

Полный блог пост находится здесь:

http://jnye.co/Posts/6/c%23-generic-search-extension-method-for-iqueryable

проект GitHub здесь (имеет несколько дополнительных расширений для OR поиска:

https://github.com/ninjanye/SearchExtensions

public static class QueryableExtensions 
{ 
    public static IQueryable<T> Search<T>(this IQueryable<T> source, Expression<Func<T, string>> stringProperty, string searchTerm) 
    { 
     if (String.IsNullOrEmpty(searchTerm)) 
     { 
      return source; 
     } 

     // The below represents the following lamda: 
     // source.Where(x => x.[property] != null 
     //    && x.[property].Contains(searchTerm)) 

     //Create expression to represent x.[property] != null 
     var isNotNullExpression = Expression.NotEqual(stringProperty.Body, Expression.Constant(null)); 

     //Create expression to represent x.[property].Contains(searchTerm) 
     var searchTermExpression = Expression.Constant(searchTerm); 
     var checkContainsExpression = Expression.Call(stringProperty.Body, typeof(string).GetMethod("Contains"), searchTermExpression); 

     //Join not null and contains expressions 
     var notNullAndContainsExpression = Expression.AndAlso(isNotNullExpression, checkContainsExpression); 

     var methodCallExpression = Expression.Call(typeof(Queryable), 
                "Where", 
                new Type[] { source.ElementType }, 
                source.Expression, 
                Expression.Lambda<Func<T, bool>>(notNullAndContainsExpression, stringProperty.Parameters)); 

     return source.Provider.CreateQuery<T>(methodCallExpression); 
    } 
} 

Это позволяет написать что-то вроде:

string searchTerm = "test"; 
var results = context.Menu.Search(menu => menu.MenuText, searchTerm).ToList(); 

//OR for Role name 
string searchTerm = "test"; 
var results = context.Menu.Search(menu => menu.Role.Name, searchTerm).ToList(); 

Вы также можете найти followi нг сообщений полезные:

Поиск метод расширения, что позволяет выполнять поиск accros несколько свойств:

http://jnye.co/Posts/7/generic-iqueryable-or-search-on-multiple-properties-using-expression-trees

Search метод расширения, что позволяет несколько или условия поиска на имущество:

http://jnye.co/Posts/8/generic-iqueryable-or-search-for-multiple-search-terms-using-expression-trees

Смежные вопросы