【问题标题】:Add Linq where condition to generic IQueryable<T>将 Linq where 条件添加到通用 IQueryable<T>
【发布时间】:2016-03-30 17:51:33
【问题描述】:

基本上我想做的是:

var validValues = new List<int>() { 1, 2, 34 };

query = query.Where(item => validValues.Contains(item.Value));

除了不知道是什么类型,我想把它作为扩展方法来做:

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;
}

我找到了这个帖子IQueryable Extension: create lambda expression for querying a column for a keyword 但这不是我想要的,我不知道如何适应我的情况......

【问题讨论】:

  • 你想达到什么目的?您是否要过滤掉有效值?因为你是 Where 扩展返回项目。
  • 尝试向 IQueryable 添加 where 条件
  • 我想保留某个属性值包含在有效值中的数据

标签: .net linq generics


【解决方案1】:

与链接的帖子类似,但这次需要动态构建Expression&lt;Func&lt;T, bool&gt;&gt;,使用Expression.Call调用Enumerable.Contains&lt;int&gt;,如下所示:

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);
}

【讨论】:

    【解决方案2】:

    这里有一个更好的版本 where 带有通用有效值集合的动态表达式:

        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);
        }
    

    用法:

    query = query.Where(item => item.Value, validValues));
    

    【讨论】:

    • 这很好用,除非我的属性是 int 类型?我接受的值列表是 List 类型的,我收到一个错误,我会检查如何修复它
    【解决方案3】:

    如果你让它与任意集合一起工作(不仅仅是 IList) - 你可以这样做:

    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));
        }
    }
    

    注意,我还使用属性访问表达式而不是将属性名称作为字符串传递 - 这更安全。像这样使用:

    var validValues = new List<int>() { 1, 2, 34 };
    query = query.WhereContains(validValues, item => item.ValidValue);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-19
      • 1970-01-01
      • 2021-04-09
      • 2014-12-11
      • 1970-01-01
      • 2021-08-13
      • 1970-01-01
      相关资源
      最近更新 更多