• .NetCore 扩展封装 Expression<Func<T, bool>> 查询条件遇到的问题


    前面的文章封装了查询条件 自己去组装条件,但是对 And  Or  这种组合支持很差,但是也不是不能支持,只是要写更多的代码看起来很臃肿

    根据 Where(Expression<Func<T, bool>>) 我们直接来处理这个,在处理这个之前其实看了下

    Expression这个对象的处理,本生里面是包含了 AndAlso 、 Or 的处理   先来看看这个会遇到什么问题?为什么不行?

    比如:

    Expression.AndAlso(first,second)

    来一段之前的扩展

     public static Expression AndExpression(this Expression expression, Expression right)
            {
                return  Expression.AndAlso(expression, right);
               
            }
    public static Expression OrExpression(this Expression expression, Expression right)
            {
               return Expression.Or(expression, right);
               
            }
    public static Expression<Func<T,bool>> ToFilter<T>(this Expression expression)
            {
                return Expression.Lambda<Func<T, bool>>(expression, Expression.Parameter(typeof(T)));
              
            }

    本质上没什么不同,最后连接都能拿到相关的表达式

    Expression filter= Expression.Constant(true, typeof(bool));
                if (!string.IsNullOrEmpty(username))
                {
                    filter = filter.AndExpression(new UosoConditions {
                        Key = "UserName",
                        Operator = UosoOperatorEnum.Contains,
                        Value = username,
                        ValueType = "string"
                    }.Parser<IdentityUser>());
                }

    按照如上写法多写几个条件,2个查询条件,2个值,感觉没问题, 但是运行到Where的时候报错误 表到时Parameter参数的个数对应不上表达式参数的个数,参数丢失了?

    参数的值跟随表达式,在组合的时候需要重新组合参数,如果直接组合表达式,参数不会发生变化所以需要处理下参数问题,对(Expression<Func<T, bool>>) 的扩展就迎刃而解了

    正确的处理方式:

       public static class ExpressionExtensions
        {
            /// <summary>
            /// 添加And条件
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="first"></param>
            /// <param name="second"></param>
            /// <returns></returns>
            public static Expression<Func<T, bool>> And<T>(
            this Expression<Func<T, bool>> first,
            Expression<Func<T, bool>> second)
            {
                return first.AndAlso<T>(second, Expression.AndAlso);
            }
            /// <summary>
            /// 添加Or条件
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="first"></param>
            /// <param name="second"></param>
            /// <returns></returns>
            public static Expression<Func<T, bool>> Or<T>(
                this Expression<Func<T, bool>> first,
                Expression<Func<T, bool>> second)
            {
                return first.AndAlso<T>(second, Expression.OrElse);
            }
            /// <summary>
            /// 合并表达式以及参数
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="expr1"></param>
            /// <param name="expr2"></param>
            /// <param name="func"></param>
            /// <returns></returns>
            private static Expression<Func<T, bool>> AndAlso<T>(
            this Expression<Func<T, bool>> expr1,
            Expression<Func<T, bool>> expr2,
            Func<Expression, Expression, BinaryExpression> func)
            {
                var parameter = Expression.Parameter(typeof(T));
    
                var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
                var left = leftVisitor.Visit(expr1.Body);
    
                var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
                var right = rightVisitor.Visit(expr2.Body);
    
                return Expression.Lambda<Func<T, bool>>(
                    func(left, right), parameter);
    
    
    
            }
    
    
            private class ReplaceExpressionVisitor
     : ExpressionVisitor
            {
                private readonly Expression _oldValue;
                private readonly Expression _newValue;
    
                public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
                {
                    _oldValue = oldValue;
                    _newValue = newValue;
                }
    
                public override Expression Visit(Expression node)
                {
                    if (node == _oldValue)
                        return _newValue;
                    return base.Visit(node);
                }
            }
        }

    使用方法就简单多了

     Expression<Func<IdentityUser, bool>> filter = u => true;
    
                if (!string.IsNullOrEmpty(username))
                {
                    filter = filter.And(c => c.UserName.Contains(username));
                }
                if (!string.IsNullOrEmpty(phone))
                {
                    filter = filter.And(c => c.PhoneNumber.Contains(phone));
                }
                if (!string.IsNullOrEmpty(email))
                {
                    filter = filter.And(c => c.Email.Contains(email));
                }

    这里值得注意的是 一定要重新赋值到 filter ,按理说扩展了Expression<Func<T, bool>> 也返回了 Expression<Func<T, bool>>  好像可以不用重新赋值,然而这里并不是这样

    如果我们直接

    filter.And(c => c.UserName.Contains(username));

    这样添加 会发现之中都是第一个参数的条件 都是 true,这是为什么呢?

    Expression<Func<IdentityUser, bool>> filter = u => true;

    下面看下这段代码其实给之前出现错误的原因是一样的?

      private static Expression<Func<T, bool>> AndAlso<T>(
            this Expression<Func<T, bool>> expr1,
            Expression<Func<T, bool>> expr2,
            Func<Expression, Expression, BinaryExpression> func)
            {
                var parameter = Expression.Parameter(typeof(T));
    
                var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
                var left = leftVisitor.Visit(expr1.Body);
    
                var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
                var right = rightVisitor.Visit(expr2.Body);
    
                return Expression.Lambda<Func<T, bool>>(
                    func(left, right), parameter);
    
    
    
            }
    var parameter = Expression.Parameter(typeof(T)); 是对 T 类中做的反射,本生合并两个带 T 的应该是没问题的,只是因为

    与 Expression<Func<IdentityUser, bool>> filter = u => true; 组合后  

    Expression.Lambda<Func<T, bool>>(
                    func(left, right), parameter);

    一直都是True,导致最后的条件都是返回 True 查询条件就无效了,所以需要重新引用赋值 filter




  • 相关阅读:
    SQL ——索引、视图和事务
    流控制语句
    SQL Server 高级编程之T-SQL 编程函数
    SQL高级编程之waitfor
    数据库主键、外键、唯一等约束
    打代码会遇到的单词
    前端词云图
    docker+mysql集群+读写分离+mycat管理+垂直分库+负载均衡
    lvs+keepalived实现Mycat的负载均衡--高可用
    mycat配置数据库集群
  • 原文地址:https://www.cnblogs.com/liyouming/p/9447984.html
Copyright © 2020-2023  润新知