Создать выражение < > для фильтрации по произвольному свойству
-
05-07-2019 - |
Вопрос
Я хочу написать фильтрующие элементы управления, которые принимают тип объекта T
и имя свойства и возвращают Expression < Func < Tol, bool > >
, который проверяет значение переданного свойства. Я не хочу использовать рефлексию, потому что боюсь, что такие выражения не могут быть использованы EF. Я не могу использовать делегаты, потому что C # не имеет делегатов для свойств. Что я могу сделать? Может быть, я должен использовать другой подход для написания этих элементов управления?
Вот мой первый подход с использованием отражения:
public string FilteringField { get; set; }
public Expression<Func<T, bool>> GetFilterExpression()
{
if (cmbValue.SelectedIndex == 1)
return (o => (bool)typeof(T).GetProperty(FilteringField).GetValue(o, null));
if (cmbValue.SelectedIndex == 2)
return (o => !(bool)typeof(T).GetProperty(FilteringField).GetValue(o, null));
return null;
}
Решение
Отражение здесь не проблема; EF даже не сможет заметить разницу. Кстати, делегатский подход не является началом (поскольку вы упоминаете EF); в конце концов, это что-то вроде:
public static IQueryable<T> Where<T>(this IQueryable<T> query,
string propertyName, object value)
{
PropertyInfo prop = typeof(T).GetProperty(propertyName);
var param = Expression.Parameter(typeof(T), "x");
var body = Expression.Equal(
Expression.Property(param, prop),
Expression.Constant(value, prop.PropertyType)
);
var predicate = Expression.Lambda<Func<T, bool>>(body, param);
return query.Where(predicate);
}
Обратите внимание, что это можно упростить с помощью Expression.PropertyOrField (propertyName)
; причина, по которой я не использовал это здесь, заключается в том, что очень удобно знать тип члена ( prop.PropertyType
) при создании константы - в противном случае вы можете получить проблемы с нулями.
Другие советы
Я знаю, что это старый ответ, но если кто-то увидит это, я создал этот проект:
https://github.com/PoweredSoft/DynamicLinq
Которые также должны быть загружены на nuget:
https://www.nuget.org/packages/PoweredSoft.DynamicLinq р>
и вы могли бы просто сделать
query.Where("FirstName", ConditionOperators.Equal, "David");