前言
最近在優化同事寫的代碼(我們的框架用的是dapperLambda),其中有一個這樣很普通的場景——界面上提供了一些查詢條件框供用戶來進行過濾數據。由於dapperLambda按條件查詢時是傳入表達式樹的參數,這樣比如其中查詢條件有一個是審核狀態,另外五個是模糊查詢,那這查詢時的表達式樹參數就要寫兩次,這樣使得代碼看起來有很多是重復的,而且如果查詢條件多的情況下,在寫那表達式樹參數時也容易漏寫或錯寫。所以我在想如果可以動態拼接這表達式樹,那這代碼就要精簡很多了。
正文
也許我的上面文字描述讓你不明覺里,那下面我就配以簡單的代碼來再說明一下這個問題:
1 Expression<Func<SysUser, bool>> exp1 = s => s.UserName.Contains("1") && s.Age > 10; 2 Expression<Func<SysUser, bool>> exp2 = s => s.UserName.Contains("1") && s.Age > 10 && s.IsEnable == 1; 3 using (var context = new DbContext().ConnectionString(connString)) 4 { 5 var result1 = context.Select<SysUser>(exp1).QueryMany(); 6 var result2 = context.Select<SysUser>(exp2).QueryMany(); 7 }
上面代碼兩次查詢,第一次查詢結果result1的結果是用戶名中包含1而且年齡大於10,而結果result2中就是在查詢結果result1的條件上再加上帳號生效這一條件。所以我們看到exp1和exp2的表達式樹絕大部分是相同的,在這個示例里看着這點重復代碼似乎還是可以接受的,但是在真實環境下,重復的代碼就不止這一點點了。因為exp2和exp1相比,exp2只是在exp1之上多加了一個條件,那我們有沒有方法可以在exp1的基礎上再加一個條件賦值給exp2呢?答案當然是可以的。
表達式擴展類:
1 public static class ExpressionExt 2 { 3 public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) 4 { 5 return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, expr2.Body), expr1.Parameters); 6 } 7 public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,Expression<Func<T, bool>> expr2) 8 { 9 return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, expr2.Body), expr1.Parameters); 10 } 11 }
上面這代碼是我們這文章的核心,我在這里順便解釋一下這個And擴展方法它是怎么做的,它這里先是使用Expression類中的靜態方法AndAlso把expr1和expr2的主體拼接在一起,如果AndAlso方法返回的是BinaryExpression類型的結果,而dapperLambda的條件參數需要的是Lambda表達式樹,所以這里我們需要通過Expression.Lambda方法來構造一個委托類型來創建一個Lambda表達樹。
那現在我們通過上面的擴展方法,再來優化一下我們最初舉的例子看下:
1 Expression<Func<SysUser, bool>> exp1 = s => s.UserName.Contains("1") && s.Age > 0; 2 Expression<Func<SysUser, bool>> exp2 =exp1.And( s => s.IsEnable == 1); 3 using (var context = new DbContext().ConnectionString(connString)) 4 { 5 var result1 = context.Select<SysUser>(exp1).QueryMany(); 6 var result2 = context.Select<SysUser>(exp2).QueryMany(); 7 }
結束語
雖然這個擴展方法就只有幾行代碼,但是如果少了這幾行代碼,在我們的代碼里可能就要上了幾十行、幾百行代碼了。有時解決問題的關鍵就是那么一個不起眼的東西,但就是這么一個不起眼的東西就能幫我們解決一些大問題。
說到這,讓我想起了一句話——每多學一點知識,就少寫一行代碼。