Add Linq, where is the condition for generic IQueryable <T>
Basically, I would like to do the following:
var validValues = new List<int>() { 1, 2, 34 };
query = query.Where(item => validValues.Contains(item.Value));
Except that I don’t know what type it is, I would like to do it as an extension method:
public static IQueryable<T> Where<T>(this IQueryable<T> source, string propertyName, IList<int> accpetedValues)
{
if (accpetedValues == null || !accpetedValues.Any() || string.IsNullOrEmpty(propertyName))
return source;
// HERE
return source;
}
I found this IQueryable Extension post : creating a lambda expression to query a column for a keyword but this is not what I want and I cannot figure out how to adapt it to my case ...
+4
3 answers
Here's the best version, where with a dynamic expression with a common common set of values:
public static IQueryable<Tsource> Where<Tsource, Tproperty>(this IQueryable<Tsource> source, Expression<Func<Tsource, Tproperty>> property, IList<int> accpetedValues)
{
var propertyName = ((MemberExpression)property.Body).Member.Name;
if (accpetedValues == null || !accpetedValues.Any() || string.IsNullOrEmpty(propertyName))
return source;
var item = Expression.Parameter(typeof(Tsource), "item");
var selector = Expression.PropertyOrField(item, propertyName);
var predicate = Expression.Lambda<Func<Tsource, bool>>(
Expression.Call(typeof(Enumerable), "Contains", new[] { typeof(Tproperty) },
Expression.Constant(accpetedValues), selector),
item);
return source.Where(predicate);
}
Application:
query = query.Where(item => item.Value, validValues));
0
, Expression<Func<T, bool>> Expression.Call, Enumerable.Contains<int> :
public static IQueryable<T> Where<T>(this IQueryable<T> source, string propertyName, IList<int> accpetedValues)
{
if (accpetedValues == null || !accpetedValues.Any() || string.IsNullOrEmpty(propertyName))
return source;
var item = Expression.Parameter(typeof(T), "item");
var selector = Expression.PropertyOrField(item, propertyName);
var predicate = Expression.Lambda<Func<T, bool>>(
Expression.Call(typeof(Enumerable), "Contains", new[] { typeof(int) },
Expression.Constant(accpetedValues), selector),
item);
return source.Where(predicate);
}
+1
If you do this to work with arbitrary collections (and not just IList), you can do it like this:
static class Extensions {
public static IQueryable<TEntity> WhereContains<TEntity, TProperty>(this IQueryable<TEntity> source, IList<TProperty> accpetedValues, Expression<Func<TEntity, TProperty>> property) {
if (accpetedValues == null || !accpetedValues.Any())
return source;
var member = property.Body as MemberExpression;
if (member == null)
return source; // better throw
string propertyName = member.Member.Name;
var containsMethod = typeof (ICollection<TProperty>).GetMethod("Contains"); // get Contains method of IList
var parameter = Expression.Parameter(typeof (TEntity), "p");
var memberAccess = Expression.Property(parameter, propertyName); // p.ValidValue (for example)
var list = Expression.Constant(accpetedValues); // your list
var body = Expression.Call(list, containsMethod, memberAccess); // list.Contains(p.ValidValue)
return source.Where(Expression.Lambda<Func<TEntity, bool>>(body, parameter));
}
}
Note. I also use a property access expression instead of passing the property name as a string - this is more type safe. Use the following:
var validValues = new List<int>() { 1, 2, 34 };
query = query.WhereContains(validValues, item => item.ValidValue);
0