【问题标题】:how to use LINQ with dynamic paramters in orderby clause如何在 orderby 子句中使用带有动态参数的 LINQ
【发布时间】:2016-03-18 02:56:07
【问题描述】:

我在 orderby linq 表达式中使用动态参数时遇到问题

  1. SearchExp函数

    public Expression<Func<EmailAflAwmMessageDM, bool>> SearchXpr(string param, string q)
    {
        if (param == "to")
            return e => e.to_msg.Contains(q);
        else if (param == "from")
            return e => e.from_msg.Contains(q);
        else if (param == "cc")
            return e => e.cc_msg.Contains(q);
        else if (param == "bcc")
            return e => e.bcc_msg.Contains(q);
        else if (param == "subject")
            return e => e.subject.Contains(q);
        else
            return e => e.body_text.Contains(q);
    }
    
  2. filterExp函数

       public Expression<Func<EmailAflAwmMessageDM, bool>> FiltertXpr(string filter, string value)
       {
        if (filter == "attachments")
        return e => e.attachments == value;
        else if (filter == "flagged")
        return e => e.flagged == value;
        else
        return e => e.seen == value;
        }
    
  3. IQueryable 函数

       private IQueryable SearchFilter(string param,string q,string filter,
           string value,string sort,string dir)
       {
          var searchXpr = SearchXpr(param, q);
          var filterXpr = FiltertXpr(filter, value);
          var emailmessage = 
          db.EmailAflAwmMessage.
          Where(filterXpr).Where(searchXpr)
          .OrderByDescending(a => a.msg_date).Select(a =>
          new
          {
           a.subject,
           a.msg_date,
          });
    
           return emailmessage;
          }
    

上面的代码可以工作,但我需要OrderBy 以动态方式。 因为我有 2 个参数 sort(表示其参数名称)和 dir(表示升序或降序)就像我想要 orderby(参数名称)dir 请帮助我,感谢您宝贵的时间和建议,并建议我用简单的方法替代。谢谢。

【问题讨论】:

    标签: c# linq linq-to-sql entity-framework-6 iqueryable


    【解决方案1】:

    我建议你阅读Expression's tree's,下面的代码是用于教学的,但我认为这会对你有所帮助:

      public static class ExpressionBuilder
        {
            private static readonly MethodInfo ToStringMethod = typeof(object).GetMethod("ToString");
            private static readonly MethodInfo StringContainsMethod = typeof(string).GetMethod("Contains");
    
            public static Func<T, object> Selector<T>(string prop)
            {
                var type = typeof(T);
                var param = Expression.Parameter(type);
                return Expression.Lambda<Func<T, object>>(Expression.Property(param, type.GetProperty(prop)), param).Compile();
            }
    
            public static Expression<Func<T, bool>> BuildFilterPredicate<T>(string q)
            {
                var query = Expression.Constant(q);
                var type = typeof(T);
                var lbdSelector = Expression.Parameter(type);
                var predicates = type.GetProperties().SelectMany(p => PredicateContainsBuilder(lbdSelector, p, query)).ToList();
                Expression body = predicates[0];
                body = predicates.Skip(1).Aggregate(body, Expression.OrElse);
                return Expression.Lambda<Func<T, bool>>(body, lbdSelector);
            }
    
            private static IEnumerable<MethodCallExpression> PredicateContainsBuilder(Expression lbdSelector, PropertyInfo prop, Expression query)
            {
    
                if (prop.PropertyType.IsClass)
                    return new List<MethodCallExpression> { Expression.Call(Expression.Call(Expression.Property(lbdSelector, prop), ToStringMethod), StringContainsMethod, query) };
    
                var properties = prop.PropertyType.GetProperties();
                return properties.Select(p => Expression.Call(Expression.Call(Expression.Property(lbdSelector, p), ToStringMethod), StringContainsMethod, query)).ToList();
            }
        }
    

    所以现在你在你的方法中这样做:

    注意:

    • 我假设实体是EmailMessage,所以我用它来生成谓词;
    • 搜索不深入;
    • 它将搜索所有属性,并且不使用string param 来定义要匹配的属性;
    private IQueryable SearchFilter(string param,string q,string filter,string value,string sort,string dir)
        {
            var emailMessage = db.EmailAflAwmMessage
                                .Where(ExpressionBuilder.BuildFilterPredicate<EmailMessage>(q))
                                .OrderBy(ExpressionBuilder.Selector<EmailMessage>(sort))
                                .Select(m=> new{m.subject,m.msg_date});        
        return emailmessage;
        }
    

    【讨论】:

    • 感谢您的回答,能否请您再次阅读我的问题,我需要什么。我需要在where子句中带有2个函数1,参数名称和文本作为q用于搜索,第二个过滤器带有参数名称和文本,是或否,第三个是参数名称和排序顺序。再次感谢
    • @adnan 但 sn-p 向您展示了如何做到这一点,我建议您链接到一篇文章,以便您了解并根据您的需要实施它。
    【解决方案2】:

    我有简单的解决方案,现在它与我合作,还有更多选择,但我只是分享我的答案:

    1. SortXpr 函数

       private IQueryable SortXpr(IQueryable<EmailAflAwmMessageDM> email ,string sort,string dir) {
      
          if (sort.Contains("to"))
          {
              if (dir.Contains("asc"))
              {
                  return email.OrderBy(e => e.to_msg);
              }
              else
              {
                  return email.OrderByDescending(e => e.to_msg);
              }
          }
          else if (sort.Contains("from"))
          {
              if (dir.Contains("asc"))
              {
                  return email.OrderBy(e => e.from_msg);
              }
              else
              {
                  return email.OrderByDescending(e => e.from_msg);
              }
          }
          else if (sort.Contains("subject"))
          {
              if (dir.Contains("asc"))
              {
                  return email.OrderBy(e => e.subject);
              }
              else
              {
                  return email.OrderByDescending(e => e.subject);
              }
          }
          else
          {
              if (dir.Contains("asc"))
              {
                  return email.OrderBy(e => e.msg_date);
              }
              else
              {
                  return email.OrderByDescending(e => e.msg_date);
              }
          }
      
      }
      
    2. FilterXpr 函数

      private Expression<Func<EmailAflAwmMessageDM, bool>>    FiltertXpr(string filter, string value)
      {
          if (filter == "attachments")
              return e => e.attachments == value;
          else if (filter == "flagged")
              return e => e.flagged == value;
          else
              return e => e.seen == value;
      }
      
    3. SearchXpr 函数

      private Expression<Func<EmailAflAwmMessageDM, bool>> SearchXpr(string param, string q)
      {
          if (param == "to")
              return e => e.to_msg.Contains(q);
          else if (param == "from")
              return e => e.from_msg.Contains(q);
          else if (param == "cc")
              return e => e.cc_msg.Contains(q);
          else if (param == "bcc")
              return e => e.bcc_msg.Contains(q);
          else if (param == "subject")
              return e => e.subject.Contains(q);
          else
              return e => e.body_text.Contains(q);
      }
      
    4. SearchFilterCondition 函数

       private IQueryable SearchFilterCondition(string param,string q
          ,string filter,string value,string sort,string dir)
       {
         var searchXpr = SearchXpr(param, q);
         var filterXpr = FiltertXpr(filter, value);
         IQueryable<EmailAflAwmMessageDM>
         EmailAflAwmMessagejc = db.EmailAflAwmMessage.Where(filterXpr).Where(searchXpr);
         return SortXpr(EmailAflAwmMessagejc, sort, dir);
       }
      

    感谢 stackoverflow 社区,感谢您的宝贵时间,再次感谢。

    【讨论】:

      猜你喜欢
      • 2013-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多