[翻譯]怎樣使用表達式樹生成動態查詢 在LINQ,表達式樹常用於結構化查詢,目標資源數據實現了 "IQueryable" . 例如,LINQ為關係型數據存儲查詢提供了 "IQueryable" 介面。C 編譯器將這些數據源的查詢編譯成運行時的表達式樹代碼。然後查詢提供程式可以遍歷表達式樹數據結構,並 ...
[翻譯]怎樣使用表達式樹生成動態查詢
在LINQ,表達式樹常用於結構化查詢,目標資源數據實現了 IQueryable. 例如,LINQ為關係型數據存儲查詢提供了 IQueryable
在LINQ中使用表達式樹來表示分配給 Expression
這節主要描述瞭如何使用表達式樹構建一個動態LINQ查詢。在編譯期,動態查詢在特殊未知的查詢的情況下是非常有用的。具體例子,一個應用程式提供了一個用戶介面,最終來允許用戶指定一個或多個謂詞來過濾數據。為了使用LINQ查詢,這種情況應用程式在運行時必須使用表達式樹來構建一個LINQ查詢。
Example
下麵這段代碼展示如何使用表達式樹去圍繞 IQueryable
數據源構造一個查詢並運行。代碼生成了一個表達式樹來表示查詢:
companies.Where(company => (company.ToLower() == "coho winery" || company.Length > 16)).OrderBy(company => company)
在命名空間 [System.Linq.Expressions](https://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions)
下有個工廠方法用來生成一個表達式樹來表示這個查詢。表示標準查詢運算符方法調用的表達式將引用這些方法的 Queryable 的實現。最終表達式樹被傳遞給 IQueryable
數據源的提供程式的 CreateQueryIQueryable
類型的查詢。通過枚舉該查詢獲得結果。
Expression<Func<string, bool>> expr = name => name.Length > 10 && name.StartsWith("G");
Console.WriteLine(expr);
AndAlsoModifier treeModifier = new AndAlsoModifier();
Expression modifierExpr = treeModifier.Modify(expr);
Console.WriteLine(modifierExpr);
string[] companies = {"Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",
"Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",
"Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",
"Blue Yonder Airlines", "Trey Research", "The Phone Company",
"Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" };
//轉化IQueryable數據源
IQueryable<string> queryableData = companies.AsQueryable();
//編寫表示謂詞參數的表達式樹
ParameterExpression pe = Expression.Parameter(typeof(string), "company");
//新建一個表達式樹來表示 'company.ToLower() == "coho winery"' 的表達式
Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
Expression right = Expression.Constant("coho winery", typeof(string));
Expression e1 = Expression.Equal(left, right);
//新建一個表達式樹來表示 'company.Length > 16' 表達式
left = Expression.Property(pe, typeof(string).GetProperty("Length"));
right = Expression.Constant(16,typeof(int));
Expression e2 = Expression.GreaterThan(left, right);
//編譯表達式樹來生成一個表示'(company.ToLower() == "coho winery" || company.Length > 16)' 的表達式
Expression predicateBody = Expression.OrElse(e1, e2);
//新建一個表達式樹來表示 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'
MethodCallExpression whereCallExpresstion = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { queryableData.ElementType },
queryableData.Expression,
Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));
//排序 OrderBy(company => company)
//新建一個表達式樹來表示 'whereCallExpression.OrderBy(company => company)'
MethodCallExpression orderCallExpresstion = Expression.Call(
typeof(Queryable),
"OrderBy",
new Type[] { queryableData.ElementType, queryableData.ElementType },
whereCallExpresstion,
Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));
//新建一個可執行的查詢表達式樹
IQueryable<string> result = queryableData.Provider.CreateQuery<string>(orderCallExpresstion);
//枚舉結果
foreach (string company in companies)
Console.WriteLine(company);
代碼中在被傳遞到 Queryable.Where
方法中,在謂詞中使用了一個固定數字。但是,你可以寫一個應用程式,來編譯在謂詞中一個依賴於用戶輸入的數字變數。你也可以根據用戶的輸入,更改查詢中調用的標準查詢操作符。
編譯代碼
- 創建新的控制台應用程式項目。
- 添加對 System.Core.dll 的引用(如果尚未引用)。
- 包括 System.Linq.Expressions 命名空間。
- 從示例中複製代碼,並將其粘貼到
Main
方法中。