[C#][LINQ]動態組Where條件

[C#][LINQ]動態組Where條件

用LINQ來組條件,只能透過Where來組合,有兩大缺點,

1.每一個條件都必需使用if來判斷是否為空值或null

2.每組合一次都必需查詢一次,

為了解決以上這兩個缺點,

所以我在網上找到一個利用泛型與foreach,來組合Where條件。

   1:   
   2:  using System;
   3:  using System.Collections.Generic;
   4:  using System.Linq;
   5:  using System.Text;
   6:  using System.IO;
   7:  using System.Data.Linq.Mapping;
   8:  using System.Reflection;
   9:  using System.Linq.Expressions;
   10:  //using EnterpriseTester;
   11:   
   12:  namespace MvcBancas.DynamicExtensions
   13:  {
   14:   //動態組合 LINQ 條件語法
   15:   //EX:
   16:   //   ////取得條件
   17:   //   //vwTargetao test = new vwTargetao();
   18:   //   //test.target_ym = vw.target_ym;
   19:   //   //test.id_no = vw.id_no;
   20:   //   //test.comm_line_code = vw.comm_line_code;
   21:   //   ////執行
   22:   //   //var Query = db.vwTargetao.AsExpandable().Find<vwTargetao>(test, true);
   23:   //   TEntity obj: 查詢條件
   24:   //   bool isAnd : true:AND  false:OR
   25:   public static class DynamicExtensions
   26:   {
   27:    public static IQueryable<TEntity> Find<TEntity>(this IQueryable<TEntity> source, TEntity obj, bool isAnd) where TEntity : class
   28:    {
   29:     if (source == null)
   30:      throw new ArgumentNullException("Source can't be null!!");
   31:     //獲得所有property的信息
   32:     PropertyInfo[] properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
   33:   
   34:     Expression condition = null;
   35:     //先構造了一個ParameterExpression對象,這裡的c,就是Lambda表達中的參數。(c=>)  
   36:     //本變量被移出了foreach循環
   37:     ParameterExpression param = Expression.Parameter(typeof(TEntity), "c");
   38:     //遍歷每個property
   39:     foreach (PropertyInfo p in properties)
   40:     {
   41:      if (p != null)
   42:      {
   43:       Type t = p.PropertyType;
   44:       //只支持value型和string型的影射
   45:       if (t.IsValueType || t == typeof(string))
   46:       {
   47:        //不為null才算做條件
   48:        if (p.GetValue(obj, null) != null)
   49:        {
   50:       //SQL Server does not support comparison of TEXT, NTEXT, XML and IMAGE ,etc
   51:       ///Only support BigInt,Bit,Char,Decimal,Money,NChar,Real,
   52:       ///Int,VarChar,SmallMoney,SmallInt,NVarChar,NVarChar(MAX),VarChar(MAX)
   53:       Attribute attr = Attribute.GetCustomAttribute(p, typeof(ColumnAttribute));
   54:       if (attr != null)
   55:       {
   56:          string dbType = (attr as ColumnAttribute).DbType;
   57:          if (dbType.Contains("Text") || dbType.Contains("NText")
   58:         || dbType.Contains("Xml") || dbType.Contains("Image")
   59:         || dbType.Contains("Binary") || dbType.Contains("DateTime")
   60:         || dbType.Contains("sql_variant") || dbType.Contains("rowversion")
   61:         || dbType.Contains("UniqueIdentifier") || dbType.Contains("VarBinary(MAX)"))
   62:          {
   63:         continue;
   64:          }
   65:       }
   66:   
   67:       if (p.Name == "EntityState") continue; //排除EntityState,執行會發生錯誤
   68:       
   69:       //此兩種型態NULL會代入最小預設值
   70:       if (p.PropertyType.FullName == "System.Decimal" || p.PropertyType.FullName == "System.DateTime") //continue;  
   71:       {
   72:          //if (p.GetValue(obj,0) == 0)
   73:          continue;        
   74:       }
   75:   
   76:       if (p.PropertyType.FullName == "System.Int32" || p.PropertyType.FullName == "System.Int16")
   77:       {
   78:          //if (p.GetValue(obj,0) == 0)
   79:          continue;
   80:       }
   81:   
   82:       //構造表達式的右邊,值的一邊
   83:       Expression right = Expression.Constant(p.GetValue(obj, null), p.PropertyType);
   84:   
   85:       //構造表達式的左邊,property一端。
   86:       Expression left = Expression.Property(param, p.Name);
   87:       
   88:       //生成篩選表達式。即c.CustomerID == "Tom"
   89:       Expression filter = Expression.Equal(left, right);
   90:       if (condition == null)
   91:       {
   92:          condition = filter;
   93:       }
   94:       else
   95:       {
   96:          if (isAnd)
   97:         condition = Expression.And(condition, filter);
   98:          else
   99:         condition = Expression.Or(condition, filter);
   100:       }
   101:        }
   102:       }
   103:      }
   104:     }
   105:     if (condition != null)
   106:     {
   107:      Expression<Func<TEntity, bool>> pred = Expression.Lambda<Func<TEntity, bool>>(condition, param);
   108:      return source.Where(pred);
   109:     }
   110:     return source;
   111:   
   112:    }
   113:   
   114:   
   115:    public static IQueryable<TEntity> Find<TEntity>(this IQueryable<TEntity> source, TEntity obj) where TEntity : class
   116:    {
   117:     return Find<TEntity>(source, obj, true);
   118:    }
   119:   
   120:   
   121:    //EX:db.Customers.WhereOr("City", new List<string> { "London", "BeiJing" }).ToList();
   122:    //類似於 in 的用法
   123:    public static IQueryable<TEntity> WhereOr<TEntity, OrType>(this IQueryable<TEntity> source, string propertyName, IEnumerable<OrType> values)
   124:    {
   125:     if (source == null)
   126:      throw new ArgumentNullException("Source can't be null!!");
   127:     ParameterExpression param = Expression.Parameter(typeof(TEntity), "p");
   128:     Expression left = Expression.Property(param, propertyName);
   129:     Expression condition = null;
   130:     foreach (OrType value in values)
   131:     {
   132:      Expression filter = Expression.Equal(left, Expression.Constant(value));
   133:      if (condition == null)
   134:       condition = filter;
   135:      else
   136:       condition = Expression.Or(condition, filter);
   137:     }
   138:     if (condition != null)
   139:      return source.Where((Expression<Func<TEntity, bool>>)Expression.Lambda(condition, param));
   140:   
   141:     return source;
   142:    }
   143:   
   144:   
   145:   
   146:   }
   147:  }

當然,這也還沒包含『like』的語法,不過依照此架構,其實也不難擴充。

最後,再來介紹,如何使用,範例如下:

   1:     //取得條件
   2:     ////targetao
   3:     targetao WhereVw = new targetao();
   4:     WhereVw.target_ym = vw.target_ym;
   5:     WhereVw.id_no = vw.id_no;
   6:     WhereVw.comm_line_code = vw.comm_line_code;
   7:   
   8:     //proj
   9:     proj WherePj = new proj();
   10:     WherePj.proj_name = vw.proj_name;
   11:   
   12:     //channels
   13:     channels WhereCh = new channels();
   14:     WhereCh.chan_name = vw.chan_name;
   15:   
   16:   
   17:   
   18:     TargetaoViewModels ViewModel = new TargetaoViewModels();
   19:   
   20:     //執行
   21:     ////多Table回傳用ViewModels
   22:     var Query = from a in db.targetao.Find<targetao>(WhereVw, true)
   23:        join b in db.proj.Find<proj>(WherePj, true)   
   24:         on a.proj_no equals b.proj_no
   25:        join c in db.channels.Find<channels>(WhereCh, true) 
   26:         on a.comm_line_code equals c.comm_line_code
   27:        select new TargetaoViewModels
   28:        {
   29:           TargetaoM = a,
   30:           ProjM = b,
   31:           ChannelsM = c
   32:        };

第一部份是傳入條件,首先要先把從畫面上的條件傳入與table相同的model中(mapping),

第二部份就是在每一個table之後,加入一個方法 Find<T>(model,true),

將條件傳入此物件中,而範例的作是多TABLE JOIN的寫法,也是可行的。

 

下載網址