動態拼接lambda表達式樹


前言

  最近在優化同事寫的代碼(我們的框架用的是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 }

結束語

 雖然這個擴展方法就只有幾行代碼,但是如果少了這幾行代碼,在我們的代碼里可能就要上了幾十行、幾百行代碼了。有時解決問題的關鍵就是那么一個不起眼的東西,但就是這么一個不起眼的東西就能幫我們解決一些大問題。

  說到這,讓我想起了一句話——每多學一點知識,就少寫一行代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM