[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:實務上是更複雜滴....