Reputation: 10890
I want to build LINQ
which will be later translated to the WHERE IN
in sql
. In regular use case I would do:
(querable
is IQuerable<T>
and arr
is IEnumerable<int>
)
querable = querable.Where(e => arr.Contains(e.Id));
BUT
my issue is that the value I want to filter (e.Id
) is dynamic, and I get it as a string. How can I do that?
Some more background: I'm doing REST API endpoint in which user can send by which column he wants to filter values, so examples would be:
filter: {"id": [1,2]}
Which I want to translate into something like queryable.Where(e => new [] {1,2}.Contains(e.Id))
filter: {"customerId": [4,5]}
Which I want to translate into something like queryable.Where(e => new [] {4,5}.Contains(e.CustomerId))
So basically my input is a column name which is a string
and list of ids which is IEnumerable<int>
I feel it can be achieved by using Expression
(similar to this answer) but I don't know how to do it.
Upvotes: 4
Views: 206
Reputation: 101483
You can do it like this:
public static class QueryableExtensions {
public static IQueryable<TEntity> WhereIn<TEntity, TValue>(this IQueryable<TEntity> query, string property, IEnumerable<TValue> values) {
// x
var arg = Expression.Parameter(typeof(TEntity), "x");
// x.Property
var prop = Expression.Property(arg, property);
// values.Contains(x.Property)
var contains = Expression.Call(
typeof(Enumerable),
"Contains",
new[] { typeof(TValue) },
Expression.Constant(values),
prop
);
// x => values.Contains(x.Property)
var lambda = Expression.Lambda<Func<TEntity, bool>>(contains, arg);
return query.Where(lambda);
}
}
Note that type of values in enumerable you pass, and property type should match for this to work (so if property is of type int - pass array of ints).
Upvotes: 2