2013-07-24 46 views
3

我要找的SEARCHTEXT任何列的查询/一般的过滤器字段映射LINQ的IQueryable的一般的过滤器

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

在这里,我给你一个示例场景现在

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

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
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.Truepredicate.Orpredicate.And

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

+0

orPredicate is not initilized它是仅用于谓词还是不同于var orPredicate = properties.Aggregate(predicate,(当前,财产)=> current.Or(CreateLike (property,search))); –

+0

对不起,打字错误,我会改变 –

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

结合简而言之名PredicateBuilder从C#。这也是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))