Generate Expression<> for filtering by a arbitrary property
-
05-07-2019 - |
Question
I want to write filtering controls which take object type T
and property name and return Expression<Func<T, bool>>
that checks value of passed property. I don't want to use reflection because I'm afraid such expressions can't be used by EF. I can't use delegates because C# doesn't have delegates for properties. What can I do? Maybe I should use different approach for writing these controls?
Here is my first approach using reflection:
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;
}
Solution
Reflection isn't a problem here; EF won't even be able to notice the difference. The delegate approach is a non-starter, by the way (since you mention EF); ultimately, it is something like:
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);
}
Note that you can make it easier with Expression.PropertyOrField(propertyName)
; the reason I haven't used that here is that it is very handy to know the member-type (prop.PropertyType
) when creating the constant - otherwise you can get problems with nulls.
OTHER TIPS
I know this an old answer but if someone see's this I've built this project:
https://github.com/PoweredSoft/DynamicLinq
Which should be downloadable on nuget as well:
https://www.nuget.org/packages/PoweredSoft.DynamicLinq
and you could simply do
query.Where("FirstName", ConditionOperators.Equal, "David");