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

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

我在使用 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 ,下面的代码是用于 didatic 的,但我认为这会对您有所帮助:

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

关于c# - 如何在 orderby 子句中使用带有动态参数的 LINQ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34236345/

相关文章:

c# - 使用 PInvoke 将点 (x,y,z) 列表从 C 返回到 C#

c# - 使用 ClickOnce 使桌面图标模糊

C# Xamarin : How to change navigation bar color?

c# - 如何创建一个接受多个 lambda 表达式作为参数的方法?

c# - 使用 LINQ 关闭与数据库的连接?

c# - 我如何定义一个类来反序列化二进制文件

c# - 如何在 Collection<T> 上使用 ToList

c# - Entity Framework 有多安全?

c# - LINQ/LAMBDA 按日期过滤查询

linq - 管理 LINQ to SQL .dbml 模型复杂性