[Expression Tree] MSDN學習系列 3-使用運算式樹狀結構建置動態查詢
private void TraditionQuery() { string sortColumn = "ProductName"; string filterColumn = "CategoryName"; string filterValue = "HTC"; IQueryable<ProductModel> data = ProductModel.GetDatas(); switch (sortColumn) { case "CategoryName": data = data.OrderBy(m => m.CategoryName); break; case "ProductName": data = data.OrderBy(m => m.ProductName); break; } switch (filterColumn) { case "CategoryName": data = data.Where(m => m.CategoryName == filterValue); break; case "ProductName": data = data.Where(m => m.ProductName == filterValue); break; } }
目前只針對2個欄位作查詢,若有n個欄位.....不就...switch到天長地久..=.=。當然不可能這樣作,我們可以使用更有效率的方法!
使用CreateQuery建立動態查詢
以下示範透過Expression.Call叫用IQueryable本身實作的OrderBy及Where方法,再透過IQueryable 資料來源提供者的 CreateQuery<TElement>(Expression)來建立查詢結果。
OrderBy
private static IQueryable<ProductModel> OrderBy(IQueryable<ProductModel> source, string sortColumn) { //傳入參數 如:m ParameterExpression pe = Expression.Parameter(source.ElementType, "m"); //回傳欄位 如:m.ProductName Expression sortExp = Expression.Property(pe, typeof(ProductModel).GetProperty(sortColumn)); //Lamba運算式 如:m=>m.ProductName Expression body = Expression.Lambda<Func<ProductModel, string>>(sortExp, new ParameterExpression[] { pe }); //呼叫OrderBy方法 MethodCallExpression OrderByCallExpression = Expression.Call( typeof(Queryable),//來源型別 "OrderBy",//指定方法名稱 new Type[] { typeof(ProductModel), typeof(string) },//body lamba使用到Expression型別,例:sortExp及pe source.Expression,//來源運算式 body); var result = (IQueryable<ProductModel>)source.Provider.CreateQuery(OrderByCallExpression); return result; }
Where
private static IQueryable<ProductModel> Where(IQueryable<ProductModel> source, string filterColumn, string filterValue) { //傳入參數 如:m ParameterExpression pe = Expression.Parameter(source.ElementType, "m"); //回傳欄位 如:m.CategoryName Expression filterExp = Expression.Property(pe, typeof(ProductModel).GetProperty(filterColumn)); //條件值 如:"HTC" ConstantExpression valueExp = Expression.Constant(filterValue, typeof(string)); //等於條件主體 如:m.CategoryName=="HTC" Expression predicateBody = Expression.Equal(filterExp, valueExp); //Lamba運算式 Expression body = Expression.Lambda<Func<ProductModel, bool>>(predicateBody, new ParameterExpression[] { pe }); //呼叫Where方法 MethodCallExpression whereCallExpression = Expression.Call( typeof(Queryable),//來源型別 "Where",//指定方法名稱 new Type[] { typeof(ProductModel) },//body lamba使用到Expression型別,例:pe source.Expression,//來源運算式 body); var result = (IQueryable<ProductModel>)source.Provider.CreateQuery(whereCallExpression); return result; }
測試程式
static void Main(string[] args) { DynamicQuery(); Console.Read(); } private static void DynamicQuery() { string sortColumn = "ProductName"; string filterColumn = "CategoryName"; string filterValue = "HTC"; IQueryable<ProductModel> data = ProductModel.GetDatas(); data = OrderBy(data, sortColumn); data = Where(data, filterColumn, filterValue); foreach (var item in data) { Console.WriteLine(item.ProductName); } }
結論
ps:實務上是更複雜滴....