今天發表了《將不確定變為確定~表達式樹是否可以有個集合,條件過濾有了新方向》文章后,馬上有朋友問起,如何實現OR查詢,如果實現AND查詢,事實上它說的可能並不完整,完整的話應該是,“如何實現N個字段進行OR運算和AND運算”呢,沒錯,我在那篇文章中,條件過濾只是針對單個字段的,是一種AND運算,也是一種條件的過濾機制,即:
有條件a1,a2,a3,它的過濾方式是先過濾a1,然后在剩下的結果里過濾a2,最后再過濾a3,它相然等同於a1 && a2 && a3,但如果要實現OR運算,我的那個程序就無能為力了,看看我們偉大的JamesJim同志寫的這個OR與AND為表達式樹實現的擴展方法吧,呵呵 。
1 /// <summary> 2 /// 條件建立者 3 /// [單元表達式主要考用用在數據庫字段或是其他集合字段中考用直接返回bool查詢的] 4 /// [考用考慮,如果一個內存集合中,考用定義一個屬性,屬性中有邏輯,例如:return str.Lenght==1;這樣的可以用到單元運算符。] 5 /// </summary> 6 public static class PredicateBuilder 7 { 8 /// <summary> 9 /// 單元 true 表達式 10 /// </summary> 11 /// <typeparam name="T">指定泛型 T</typeparam> 12 /// <returns>true</returns> 13 public static Expression<Func<T, bool>> True<T>() 14 { 15 return item => true; 16 } 17 18 /// <summary> 19 /// 單元 false 表達式 20 /// </summary> 21 /// <typeparam name="T">指定泛型 T</typeparam> 22 /// <returns>false</returns> 23 public static Expression<Func<T, bool>> False<T>() 24 { 25 return item => false; 26 } 27 28 /// <summary> 29 /// 雙元 Or 表達式 30 /// </summary> 31 /// <typeparam name="T">指定泛型 T</typeparam> 32 /// <param name="exprleft">左表達式</param> 33 /// <param name="exprright">右表達式</param> 34 /// <returns>返回合並表達式</returns> 35 public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exprleft, Expression<Func<T, bool>> exprright) 36 { 37 var invokedExpr = Expression.Invoke(exprright, exprleft.Parameters.Cast<Expression>()); 38 return Expression.Lambda<Func<T, bool>>(Expression.Or(exprleft.Body, invokedExpr), exprleft.Parameters); 39 } 40 41 /// <summary> 42 /// 雙元 And 表達式 43 /// </summary> 44 /// <typeparam name="T">指定泛型 T</typeparam> 45 /// <param name="exprleft">左表達式</param> 46 /// <param name="exprright">右表達式</param> 47 /// <returns>返回合並表達式</returns> 48 public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> exprleft, Expression<Func<T, bool>> exprright) 49 { 50 var invokedExpr = Expression.Invoke(exprright, exprleft.Parameters.Cast<Expression>()); 51 return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(exprleft.Body, invokedExpr), exprleft.Parameters); 52 } 53 }
再配合我的統一條件功能類,進行一下改造:
1 /// <summary> 2 /// 功能:條件過濾類 3 /// 作者:張占嶺 4 /// 日期:2012-6-7 5 /// </summary> 6 public class PredicateList<TEntity> : IEnumerable<Expression<Func<TEntity, bool>>> where TEntity : class 7 { 8 List<Expression<Func<TEntity, bool>>> expressionList; 9 public PredicateList() 10 { 11 expressionList = new List<Expression<Func<TEntity, bool>>>(); 12 } 13 /// <summary> 14 /// 添加到集合 15 /// </summary> 16 /// <param name="predicate"></param> 17 public void Add(Expression<Func<TEntity, bool>> predicate) 18 { 19 expressionList.Add(predicate); 20 } 21 /// <summary> 22 /// Or操作添加到集合 23 /// </summary> 24 /// <param name="exprleft"></param> 25 /// <param name="exprright"></param> 26 public void AddForOr(Expression<Func<TEntity, bool>> exprleft, Expression<Func<TEntity, bool>> exprright) 27 { 28 expressionList.Add(exprleft.Or(exprright)); 29 } 30 /// <summary> 31 /// And操作添加到集合 32 /// </summary> 33 /// <param name="exprleft"></param> 34 /// <param name="exprright"></param> 35 public void AddForAnd(Expression<Func<TEntity, bool>> exprleft, Expression<Func<TEntity, bool>> exprright) 36 { 37 expressionList.Add(exprleft.And(exprright)); 38 } 39 40 #region IEnumerable 成員 41 42 public IEnumerator GetEnumerator() 43 { 44 return expressionList.GetEnumerator(); 45 } 46 47 #endregion 48 49 #region IEnumerable<Expression<Func<TEntity>>> 成員 50 51 IEnumerator<Expression<Func<TEntity, bool>>> IEnumerable<Expression<Func<TEntity, bool>>>.GetEnumerator() 52 { 53 return expressionList.GetEnumerator(); 54 } 55 56 #endregion 57 }
嘿嘿,這樣就可以把一些用到做AND或者OR的條件先進行組成,最后再和其它條件一起過濾,就OK了,呵呵。
調用時,可以這樣:
1 PredicateList<UserBases> zzl = new PredicateList<UserBases>(); 2 Expression<Func<UserBases, bool>> exp_name = i => i.Name.Contains("zzl"); 3 Expression<Func<UserBases, bool>> exp_id = i => i.UserID == 1; 4 zzl.AddForOr(exp_name, exp_id); 5 GetModel(zzl).ForEach(i => Console.WriteLine(i.Name)); 6 Console.ReadKey();
OK,世界上對於i.Name和i.UserID的賦值,是我們在業務上判斷過的,在PredicateList中存在的過濾條件就是真實要被過濾的。