如何在 orderby 子句中使用带有动态参数的 LINQ

how to use LINQ with dynamic paramters in orderby clause

我在使用 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 请帮助我,感谢您宝贵的时间和建议,并建议我使用简单的方法进行任何替代。谢谢。

我建议您阅读有关 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();
        }
    }

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

Note:

  • I supose that the entity is EmailMessage so i use that to generate the predicate;
  • It doesn't search in depth;
  • it will search in all properties and doesn't use the string param to define what property to match;
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;
    }

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

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

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