.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
相關文章
相關標籤/搜索