【问题标题】:LINQ Filter Implementation with Expressions带有表达式的 LINQ 过滤器实现
【发布时间】:2013-12-16 22:45:34
【问题描述】:

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

需要帮助将多个表达式组合成单个表达式

 Expression<Func<T, bool>> 

举例

表格列

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

到目前为止我已经实现了

  /// <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;
        }

【问题讨论】:

  • 您在过去 24 小时内问了 3 次几乎相同的问题...

标签: c# linq


【解决方案1】:

我创建了一些你应该可以使用的搜索 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();

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

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

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

【讨论】:

    【解决方案2】:

    感谢 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;
            }
    

    【讨论】:

      猜你喜欢
      • 2013-08-29
      • 1970-01-01
      • 1970-01-01
      • 2019-07-26
      • 2014-11-06
      • 1970-01-01
      • 2012-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多