2013-11-14 3 views
2

Привет Я создаю приложение winform в C#.Как написать общее дерево выражений для данных фильтра в C#

Я использую EF5 для работы с базой данных.

и для привязки данных к моему DataGridViews я создал компонент из BindingSource, который имеет метод Bind(), которые выполняются это событие:

private object bindingSourceTbl1_DataSourceBinding(object sender, EventArgs e) 
{ 
    using (SampleDbEntities dbo = new SampleDbEntities()) 
    { 
     return(from x in dbo.Tbl1 
      where x.Id == (int)comboBoxPerson.SelectedValue 
      select x).Take(1000).ToList(); 
    } 
} 

, потому что моя база данных имеют много больших объемы данных я выборки парциальные данных. и я использую поиск для получения записи соответствия. для этого я создал компонент SearchPanel, который создает текстовые поля для фильтрации каждого столбца в моей сетке.

на теперь я хочу, чтобы отправить дерево выражения в моем случае в качестве параметра, чтобы присоединиться к где положение так: существует

private object bindingSourceTbl1_DataSourceBinding(object sender, EventArgs e,Expression whereClause) 
{ 
    using (SampleDbEntities dbo = new SampleDbEntities()) 
    { 
     return(from x in dbo.Tbl1 
      where x.Id == (int)comboBoxPerson.SelectedValue && whereClause 
      select x).Take(1000).ToList(); 
    } 
} 

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

это означает, что я не могу вернуться, как

< Expression Func < AnyDbSet, BOOL >>

и я не знаю, как это сделать?

Благодаря

ответ

6

Если вам нужно просто &&, то это полезно, чтобы понять, что coll.Where(x => a(x) && b(x)) (где a(x) и b(x) любые логические выражения, которые работают с x) логически такой же, как coll.Where(x => a(x)).Where(x => b(x)). Что это означает, что вы можете переписать код, чтобы что-то вроде:

List<Tbl1Type> GetTbl1Values(Expression<Func<Tbl1Type, bool>> whereClause) 
{ 
    using (SampleDbEntities dbo = new SampleDbEntities()) 
    { 
     return dbo.Tbl1 
      .Where(x => x.Id == (int)comboBoxPerson.SelectedValue) 
      .Where(whereClause) 
      .Take(1000).ToList(); 
    } 
} 

Если вы также необходимы для поддержки || или более сложных комбинаций, вы могли бы использовать LINQKit.

Это просто оставляет вопрос о создании выражения из имени свойства. Вы можете использовать для этого тип Expression. Например, что-то вроде:

static Expression<Func<T, bool>> CreateWhereClause<T>(
    string propertyName, object propertyValue) 
{ 
    var parameter = Expression.Parameter(typeof(T)); 
    return Expression.Lambda<Func<T, bool>>(
     Expression.Equal(
      Expression.Property(parameter, propertyName), 
      Expression.Constant(propertyValue)), 
     parameter); 
} 
+0

спасибо. Я решил проблему с вашим решением. но все же у меня есть проблема. потому что мне нужно искать данные с вводом значения фильтра. Мне нужно преобразовать свойства в строку, но выражение не поддерживало это. например, ему не удалось преобразовать десятичный или двойной код в строку моего кода: –

+0

var propInfo = this.dataSourceItemsType.GetProperty (fieldsName [i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.GetField); Выражение columnExpr = Expression.Property (entityParameter, propInfo); if (propInfo.PropertyType! = Typeof (String)) { columnExpr = Expression.Convert (columnExpr, typeof (String)); } Я искал эту проблему, и я увидел, что эта проблема является ошибкой в ​​деревьях выражений. Можете ли вы помочь мне решить ее? –

+1

@noorashegh Я не думаю, что это ошибка, 'Convert' является эквивалентом кастинга, и вы не можете просто использовать' decimal' для 'string' в C#. Вместо этого вы можете создать выражение, которое вызывает ['SqlFunctions.StringConvert'] (http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions.stringconvert). – svick

0

ваш может использовать dynamic linq. вот пример:

var result = northwind.Products 
    .Where("CategoryID = 3 AND UnitPrice > 3") 
    .OrderBy("SupplierID"); 

===

private object bindingSourceTbl1_DataSourceBinding(object sender, EventArgs e,Expression whereClause) 
{ 
    using (SampleDbEntities dbo = new SampleDbEntities()) 
    { 
     var q = from x in dbo.Tbl1 
      where x.Id == (int)comboBoxPerson.SelectedValue && whereClause 
      select x); 
     q = q.Where(whereClause)// your must reference dynamic linq library. 
           //whereClause is expression 
       .Take(100); 
     return q.ToList(); 

    } 

}

+0

Не могли бы вы объяснить, как именно вы будете использовать Dynamic LINQ в этом случае? – svick

+0

Я снова редактирую свой ответ. – Kain

0

Я бы рекомендовал использовать в PredicateBuilder Джозефом Albahari. Вы можете найти его на http://www.albahari.com/nutshell/predicatebuilder.aspx.

+1

PredicateBuilder сам по себе недостаточно, потому что он создает выражение, которое EF не примет. – svick

+0

Я использовал его раньше, но я не знаю, как использовать его для моей цели. У меня много сетки, которые я хочу заполнить фильтрами и получить новые правильные данные из базы данных. и у меня есть один метод для генерации моего предиката для отправки методу связывания, который существует в моем компоненте, и в этом методе у меня есть строковый массив, который содержит имя полей и один массив строк, содержащий значения фильтра, а также тип данных типа typeof (tbl1). –

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