[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