2011-07-08 3 views
1

У меня есть приложение winforms, которое в основном загружает кучу данных из базы данных с использованием структуры сущностей и отображает ее на gridview.Динамические запросы Linq для нескольких фильтров времени исполнения

Для этого сценария, рассмотрит объект, связанный с GridView быть таким:

public class Person 
{ 
    public string name; 
    public string sex; 
    public int age; 
} 

Я хотел бы дать пользователю возможность отфильтровать результаты по GridView, используя ряд фильтров на котором он мог выбрать колонку, которую он хочет фильтровать (возраст, пол, имя), оператор (больше, равно, содержит и т. д.) и значение.

Класс фильтра будет что-то вроде этого:

public class filter 
{ 
    public string column; 
    public string operator; 
    public string value; 
} 

Мой вопрос: как я могу применить эти фильтры к данным отображаются на GridView с помощью динамически создаваемых запросов Linq?

ответ

2

Вы могли бы попробовать использовать библиотеку динамического LINQ:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Или вы можете условно добавить фильтры запросов:

var dc = new MyDataContext(); // wrap with using block in production 
var query = dc.MyTable.AsQueryable(); 

if(filter1) 
    query = query.Where(i=>i.Name.Contains(text)); 

if(filter2) 
    query = query.Where(i=>i.Age == age); 
3

Попробуйте использовать деревья выражений для создания лямбды динамически против ваших данных ,

Вот пример реализации:

void Main() 
{ 
    var fieldName = "LastName"; 
    var value = "test"; 

    var db = new List<Person>() { 
     new Person() { name = "fred jones", sex = "male", age = 55 }, 
     new Person() { name = "samantha jones", sex = "female", age = 45 }, 
     new Person() { name = "cindy jones", sex = "female", age = 6 } 
    }; 

    // single query 
    db.Where(Person.GetFilter("sex", "==", "female").Compile()).Dump(); 

    // OR example 
    db.Where( 
     PredicateBuilder.Or<Person>(
      Person.GetFilter("sex", "==", "male"), 
      Person.GetFilter("age", "<", 50) 
     ).Compile() 
    ).Dump(); 

} 
class Person 
{ 
    public string name; 
    public string sex; 
    public int age; 

    public static Expression<Func<Person,bool>> GetFilter<T>(string column, string @operator, T value) 
    { 
     var ops = new Dictionary<string, Func<Expression, Expression, Expression>>() { 
      { "==", (x,y) => Expression.Equal(x,y) }, 
      { "<=", (x,y) => Expression.LessThanOrEqual(x,y) }, 
      { ">=", (x,y) => Expression.GreaterThanOrEqual(x,y) }, 
      { ">", (x,y) => Expression.GreaterThan(x,y) }, 
      { "<", (x,y) => Expression.LessThan(x,y) }, 
     }; 

     var param = Expression.Parameter(typeof(Person)); 
     var deref = Expression.PropertyOrField(param, column); 
     var testval = Expression.Constant(value); 

     return Expression.Lambda<Func<Person,bool>>(
      ops[@operator](deref, testval), 
      param); 
    } 
} 

Примечание Я использовал LINQPad, чтобы проверить это, чтобы заменить .dump() вызов с тем, что уместно в вашем контексте для отображения данных. Для построения операторов OR или AND требуется класс PredicateBuilder. Кроме того, это произойдет неэффективно, если неправильный тип передается как параметр значения (строка, переданная при сравнении возраста, например, бросает «InvalidOperationException: двоичный оператор Equal не определен для типов« System.String »и« System.Int32 » ".).

Если кто-нибудь может сказать мне лучший способ справиться с преобразованием строкового представления оператора в класс Expression, сообщите мне, поскольку я не очень доволен вышеуказанным способом, но это было самым быстрым, что я мог подумать в то время.

Смежные вопросы