I'm trying to make a generic filtering class, that will receive a property accessor and check if it's within allowed values. So the signature of the filter would be:
class PropertyFilter<TItem, TProperty>
{
PropertyFilter(Expression<Func<TItem, TProperty>> accessor, IEnumerable<TProperty> allowedValues);
IQueryable<TItem> Filter(IQueryable<TItem> items);
}
and usage
var filter = new PropertyFilter<Entity, string>(e => e.Name, new [] { "NameA", "NameB" });
await filter.Filter(dbContext.Entities).ToListAsync();
The thing has to be IQueryable compatible, so I need to compose an expression. From an expression of form x => x.Property I need to create an expression Expression<Func<TItem, bool>> equivalent to x => allowedValues.Contains(x.Property). From what I've seen I am able to do basicaly anything with the expression using Visitors and whatnot, but for one I don't know what are the rules of translating expression to SQL and what I cannot do or I break it, and also the use-case seems too simple to warrant that much code as would go into implementing my own visitors and testing all of that. Is there a short way to do this or maybe a reliable library that has already figured it out and is compatible with .NET Core 3.0 and EF Core 3.0 previews?
Untested, but this should work?
static Expression<Func<TItem, bool>> Contains<TItem, TProperty>(
Expression<Func<TItem, TProperty>> accessor,
IEnumerable<TProperty> allowedValues)
{
var wrapped = new { allowedValues };
var body = Expression.Call(typeof(Enumerable), nameof(Enumerable.Contains),
new[] { typeof(TProperty) },
Expression.PropertyOrField(Expression.Constant(wrapped), nameof(allowedValues)),
accessor.Body);
return Expression.Lambda<Func<TItem, bool>>(body, accessor.Parameters);
}
You should be able to pass the result of this to Queryable.Where.
Note that wrapped here is to add a layer of indirection that the receiving LINQ query parser might want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With