Linq IQueryable通用过滤器

时间:2013-07-24 11:41:43

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

我正在寻找任何列/字段映射的查询中的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表中,我提供了一个搜索框来过滤输入文本的结果,它可以匹配以下任何列/菜单类属性值,我想在服务器中执行此搜索方面,我该如何实施呢。

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

2 个答案:

答案 0 :(得分:4)

您可以使用表达式:

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))

答案 1 :(得分: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

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