.NetCore 扩展封装 Expression> 查询条件遇到的问题

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

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

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

好比:this

Expression.AndAlso(first,second)

来一段以前的扩展spa

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

 

本质上没什么不一样,最后链接都能拿到相关的表达式code

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>>) 的扩展就迎刃而解了blog

正确的处理方式:string

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

使用方法就简单多了it

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
相关文章
相关标签/搜索