【问题标题】:Linq IQueryable Generic FilterLinq IQueryable 通用过滤器
【发布时间】:2013-07-24 11:41:43
【问题描述】:

我正在为任何列/字段映射的查询中的 searchText 寻找通用过滤器

public static IQueryable<T> Filter<T>(this IQueryable<T> source, string searchTerm)
{
   var propNames = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(e=>e.PropertyType == typeof(String)).Select(x => x.Name).ToArray();


 //I am getting the property names but How can I create Expression for

 source.Where(Expression)
}

这里我给你一个示例场景

现在从我在 Asp.net MVC4 中的 HTML5 表中,我提供了一个搜索框来过滤输入文本的结果,它可以匹配以下任何列/菜单类属性值,我想在服务器中进行此搜索side ,我该如何实现呢。

EF 模型类

 public partial class Menu
    {
        public int Id { get; set; }
        public string MenuText { get; set; }
        public string ActionName { get; set; }
        public string ControllerName { get; set; }
        public string Icon { get; set; }
        public string ToolTip { get; set; }
        public int RoleId { get; set; }

        public virtual Role Role { get; set; }
    }

【问题讨论】:

    标签: c# linq entity-framework c#-4.0


    【解决方案1】:

    您可以使用表达式:

    private static Expression<Func<T, bool>> GetColumnEquality<T>(string property, string term)
    {
        var obj = Expression.Parameter(typeof(T), "obj");        
    
        var objProperty = Expression.PropertyOrField(obj, property);
        var objEquality = Expression.Equal(objProperty, Expression.Constant(term));
    
        var lambda = Expression.Lambda<Func<T, bool>>(objEquality, obj);
    
        return lambda;
    }
    
    public static IQueryable<T> Filter<T>(IQueryable<T> source, string searchTerm)
    {
        var propNames = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                 .Where(e => e.PropertyType == typeof(string))
                                 .Select(x => x.Name).ToList();
    
        var predicate = PredicateBuilder.False<T>();
    
        foreach(var name in propNames)
        {
            predicate = predicate.Or(GetColumnEquality<T>(name, searchTerm));
        }
    
        return source.Where(predicate);
    }
    

    在 NutShell 中结合来自 C# 的名称 PredicateBuilder。这也是LinqKit 的一部分。

    例子:

    public class Foo
    {
        public string Bar { get; set; }
        public string Qux { get; set; }
    }
    
    Filter<Foo>(Enumerable.Empty<Foo>().AsQueryable(), "Hello");
    
    // Expression Generated by Predicate Builder
    // f => ((False OrElse Invoke(obj => (obj.Bar == "Hello"), f)) OrElse Invoke(obj => (obj.Qux == "Hello"), f))
    

    【讨论】:

      【解决方案2】:
      void Main()
      {
         // creates a clause like 
         // select * from Menu where MenuText like '%ASD%' or ActionName like '%ASD%' or....
          var items = Menu.Filter("ASD").ToList();
      }
      
      // Define other methods and classes here
      public static class QueryExtensions
      {
          public static IQueryable<T> Filter<T>(this IQueryable<T> query, string search)    
          {           
              var properties = typeof(T).GetProperties().Where(p => 
                      /*p.GetCustomAttributes(typeof(System.Data.Objects.DataClasses.EdmScalarPropertyAttribute),true).Any() && */
                      p.PropertyType == typeof(String));        
              
              var predicate = PredicateBuilder.False<T>();
              foreach (var property in properties )
              {
                 predicate = predicate.Or(CreateLike<T>(property,search));
              }
              return query.AsExpandable().Where(predicate);
          }
          private static Expression<Func<T,bool>> CreateLike<T>( PropertyInfo prop, string value)
          {       
              var parameter = Expression.Parameter(typeof(T), "f");
              var propertyAccess = Expression.MakeMemberAccess(parameter, prop);                    
              var like = Expression.Call(propertyAccess, "Contains", null, Expression.Constant(value,typeof(string)));
      
              return Expression.Lambda<Func<T, bool>>(like, parameter);       
          }
      
      }
      

      您需要添加对LinqKit 的引用才能使用 PredicateBuilder 和 AsExpandable 方法 否则无法与 EF 一起使用,只能与 Linq to SQL 一起使用

      如果您想要Col1 like '%ASD%' AND Col2 like '%ASD%' et,请将PredicateBuilder.False 更改为PredicateBuilder.True 并将predicate.Or 更改为predicate.And

      您还需要找到一种方法来通过您自己的自定义属性(例如在部分类中定义)来区分映射属性

      【讨论】:

      • orPredicate 未初始化是它只是谓词还是不同,如 var orPredicate = properties.Aggregate(predicate, (current, property) => current.Or(CreateLike(property, search))) ;
      • 对不起,打错了,我改一下
      • 非常感谢,真的很有帮助如何在表达式中使用Contains时忽略大小写
      • 欢迎,我认为不区分大小写,这取决于服务器的排序规则。
      • 无法为 .Net 4.6 框架安装 LinqKit 包“Binbin.Linq.PredicateBuilder”
      猜你喜欢
      • 1970-01-01
      • 2015-04-18
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 2021-01-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多