程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> c# 經驗談:巧用Expression表達式 解決類似於sql中 select in 的查詢(適合於中小型項目)

c# 經驗談:巧用Expression表達式 解決類似於sql中 select in 的查詢(適合於中小型項目)

編輯:C#入門知識

我們在項目經常會碰到一些特殊需求 例如下拉框是復選的,查詢條件是根據下拉框中復選項進行拼接

 \

 

看到此圖後大家肯定會說,這很簡單嘛
將所有的選項 拼成“'1-3','5-9'”  然後放到 in 的字句後面,一查就出來了。
這樣做的確在邏輯上沒有問題,可是大家有沒有想過這個問題,過度的和業務耦合雖然能夠解決
現在的需求但是卻犧牲了代碼優雅和可維護性
 
其實本文的目的是想利用Expression表達式在linq查詢中實現一個優雅的解決方案,
同時也會給大家一個用Expression去拼接sql的思路
 
先上代碼
      public static Expression<Func<T, bool>> GetConditionExpression<T>(string[] options, string fieldName)
        {
            ParameterExpression left = Expression.Parameter(typeof(T), "c");//c=>
            Expression expression = Expression.Constant(false);
            foreach (var optionName in options)
            {
                Expression right = Expression.Call
                       (
                          Expression.Property(left, typeof(T).GetProperty(fieldName)),  //c.DataSourceName
                          typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),// 反射使用.Contains()方法                        
                         s Expression.Constant(optionName)           // .Contains(optionName)
                       );
                expression = Expression.Or(right, expression);//c.DataSourceName.contain("") || c.DataSourceName.contain("")
            }
            Expression<Func<T, bool>> finalExpression
                = Expression.Lambda<Func<T, bool>>(expression, new ParameterExpression[] { left });
            return finalExpression;
        }
復制代碼
我想用逆推的方式說明下這段代碼,其實我們查詢的目的要實現這樣的效果 , someList.where(c=>c.Name.contains("someName")||c.Name.Contains("someName")||...)
1. 首先我們要確定返回什麼樣的表達式,根據經驗.where後面是需要一個Expression<Func<T, bool>> 這樣的一個表達式,所以方法的返回類型已經能確定下來了
2. 接下來的任務是拼接類似於c=>c.Name.Contains("") 這樣的表達式,按照自左向右的原則,左側表達式參數c很好理解 就是T,那麼這個表達式的參數也就搞定了,
可以用Expression.Parameter方法來實現,該方法目的是將類型反射並且映射給表達式中的匿名變量 “c” (也可以理解成將參數常量封裝成表達式)
3. 接著是表達式右側的拼接
 再次仔細看下這段代碼
Expression right = Expression.Call
 (                          
     Expression.Property(left, typeof(T).GetProperty(fieldName)),  //c.DataSourceName     首先是反射獲取c的一個屬性               
     typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),// 聲明一個string.Contains的方法     c.DataSourceName.Contains()                反射使用.Contains()方法 
     Expression.Constant(optionName)           //  c.DataSourceName.Contains(optionName)               封裝常量      
 );
  為什麼要使用Expression.Call ?
(因為c.Name.contains 屬於string.contains()這個方法所以我們必須將該方法封裝成表達式,Expression.Call的功能就是將方法封裝成表達式)
 這時候大家會問contains什麼呢? 當然常量option雖然是string類型,但是仍需封裝成表達式,Expression.Constant(optionName) 起到了封裝常量的作用
 於是c=>c.屬性.Contains(常量) 這個表達式搞定,可是還是有問題:怎麼加上“||” ,聰明的你已經有了答案,Expression.Or()
 
4 最後一步當然非常關鍵,就像產品需要通過流水線進行包裝組合,表達式也不例外:
Expression.Lambda<Func<T, bool>>(expression, new ParameterExpression[] { left });
對於整個表達式來說,左側是參數表達式(ParameterExpression),Expression.Lambda就是=>符號,就右側表達式和參數表達式通過lambda符號進行組合,搞定www.2cto.com
 
這樣的話,你只需傳入一個字符串數組就能在Linq中實現類似於sql中select in 的效果了,
很多朋友肯定會問,既然能夠用自定義表達式搞定,那麼可不可以將表達式的思路用於拼接sql?
答案是肯定的。但是如果業務邏輯非常復雜,而且難以把握,還是建議用ado 配合存過實現

 摘自 逆時針の風

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved