怎么样使用表明式树生成动态查询

[翻译]哪些使用表明式树生成动态查询

在LINQ,表明式树常用于结构化查询,目的资源数量实现了
IQueryable.
例如,LINQ为关系型数据存储查询提供了
IQueryable
接口。C#编译器将这个数据源的查询编译成运行时的表明式树代码。然后查询提供程序可以遍历表明式树数据结构,并转化为方便于数据源的查询语言。

在LINQ中利用表明式树来代表分配给
Expression
类型的兰姆da表达式变量。

这节首要描述了怎么样行使表明式树构建一个动态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 数据源的提供程序的
CreateQuery(Expression)
实现,以创制一个可举办的 IQueryable
类型的查询。通过枚举该查询得到结果。

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 方法中。