[Expression Tree] LINQ動態欄位查詢
動態查詢欄位
如下程式,相關註解已寫在每行程式上方,唯一較特別的是此方法傳入的IQueryable是ProductModel但回傳的是ProductTargetModel,這是因為在Linq To Entities的查詢預設不支援同一型別的回傳。 private static IQueryable<ProductTargetModel> SelectDynamicColumns(IQueryable<ProductModel> source, params string[] columns)
{
//傳入參數 如:m
ParameterExpression parSource = Expression.Parameter(source.ElementType, "m");
Type targetType = typeof(ProductTargetModel);
//目標型別的建構式
var ctor = Expression.New(targetType);
List<MemberAssignment> assignment = new List<MemberAssignment>();
foreach (var column in columns)
{
//來源屬性
var sourceValueProperty = source.ElementType.GetProperty(column);
//目標屬性
var targetValueProperty = targetType.GetProperty(column);
//建立參數與欄位節點 如:m.CategoryName
Expression columnExp = Expression.Property(parSource, sourceValueProperty);
//建立成員指定節點 如:CategoryName=m.CategoryName
var displayValueAssignment = Expression.Bind(targetValueProperty, columnExp);
assignment.Add(displayValueAssignment);
}
//將目標型別的成員初始化 例:new ProductTargetModel(){CategoryName=m.CategoryName,...}
var memberInit = Expression.MemberInit(ctor, assignment.ToArray());
//建立Lamba運算式 例: m => new ProductTargetModel(){CategoryName=m.CategoryName,...}
Expression body = Expression.Lambda<Func<ProductModel, ProductTargetModel>>(memberInit, new ParameterExpression[] { parSource });
//呼叫Select方法
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),//來源型別
"Select",//指定方法名稱
new Type[] { typeof(ProductModel), typeof(ProductTargetModel) },//body lamba使用到Expression型別,例:pe及回傳型別
source.Expression,//來源運算式
body);
var result = (IQueryable<ProductTargetModel>)source.Provider.CreateQuery(whereCallExpression);
return result;
}
測試程式
static void Main(string[] args)
{
//DynamicQuery();
DynamicColumn();
Console.Read();
}
private static void DynamicColumn()
{
IQueryable<ProductModel> data = ProductModel.GetDatas();
var dynamicResult = SelectDynamicColumns(data, "ProductName", "CategoryName");
foreach (var item in dynamicResult)
{
Console.WriteLine(item.ProductName + "-" + item.CategoryName);
}
}
參考來源
http://stackoverflow.com/questions/12701737/expression-to-create-an-instance-with-object-initializer
範例程式
https://github.com/kimx/ExpressionLab