使用表达式实现LINQfilter

在MVC4中,我向用户提供搜索框以搜索表中的任何值。 所以我在C#中的服务器端实现了通用过滤条件

需要帮助来组合多个表达式以形成单个表达式

Expression<Func> 

例如

表格列

MenuText,角色名称(Role.Name映射),ActionName

现在,如果用户在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;} } 

到目前为止我已经实施了

  ///  /// string[] properties property.Name (MenuText, ActionName), including deeper Mapping names such as (Role.Name) ///  public static Expression<Func> FilterKey(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> predicate = PredicateBuilder.False(); 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> expression } return predicate; } ///  /// To Get Deeper Properties such as Role.Name Expressions ///  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; } 

我已经创建了一些你应该可以使用的搜索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 Search(this IQueryable source, Expression> 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>(notNullAndContainsExpression, stringProperty.Parameters)); return source.Provider.CreateQuery(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(); 

您可能还会发现以下post很有用:

搜索扩展方法,允许搜索accros多个属性:

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

搜索扩展方法,允许在属性上使用多个或搜索条件:

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

感谢NinjaNye,我借用了BuildOrExpression解决了我的问题

这是解决方案

  public static Expression> FilterKey(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(null, (current, ex) => BuildOrExpression(current, ex)); return Expression.Lambda>(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; }