方法 : 式ツリーを使用して動的クエリをビルドする (C#)How to: Use Expression Trees to Build Dynamic Queries (C#)

LINQ では、IQueryable<T> を実装するデータ ソースをターゲットとする構造化されたクエリを表すために、式ツリーが使われます。In LINQ, expression trees are used to represent structured queries that target sources of data that implement IQueryable<T>. たとえば、LINQ プロバイダーは、リレーショナル データ ストアのクエリを行うために、IQueryable<T> インターフェイスを実装します。For example, the LINQ provider implements the IQueryable<T> interface for querying relational data stores. C# コンパイラは、このようなデータ ソースをターゲットとするクエリをコンパイルして、実行時に式ツリーを作成するコードを生成します。The C# compiler compiles queries that target such data sources into code that builds an expression tree at runtime. クエリ プロバイダーは式ツリー データ構造を走査して、データ ソースに適したクエリ言語に変換できます。The query provider can then traverse the expression tree data structure and translate it into a query language appropriate for the data source.

LINQ では、Expression<TDelegate> 型の変数に代入されるラムダ式を表すためにも、式ツリーが使われます。Expression trees are also used in LINQ to represent lambda expressions that are assigned to variables of type Expression<TDelegate>.

このトピックでは、式ツリーを使って動的な LINQ クエリを作成する方法について説明します。This topic describes how to use expression trees to create dynamic LINQ queries. 動的クエリは、コンパイル時にクエリの詳細がわからない場合に便利です。Dynamic queries are useful when the specifics of a query are not known at compile time. たとえば、データをフィルター処理するための述語をエンド ユーザーが指定できるユーザー インターフェイスをアプリケーションで提供することがあります。For example, an application might provide a user interface that enables the end user to specify one or more predicates to filter the data. クエリに LINQ を使うには、このようなアプリケーションでは式ツリーを使って実行時に LINQ クエリを作成する必要があります。In order to use LINQ for querying, this kind of application must use expression trees to create the LINQ query at runtime.

Example

次の例では、式ツリーを使って IQueryable データ ソースに対するクエリを作成して実行する方法を示します。The following example shows you how to use expression trees to construct a query against an IQueryable data source and then execute it. このコードは、次のクエリを表す式ツリーを作成します。The code builds an expression tree to represent the following query:

companies.Where(company => (company.ToLower() == "coho winery" || company.Length > 16)).OrderBy(company => company)

クエリ全体を構成する式を表す式ツリーの作成には、System.Linq.Expressions 名前空間のファクトリ メソッドが使われます。The factory methods in the System.Linq.Expressions namespace are used to create expression trees that represent the expressions that make up the overall query. 標準クエリ演算子メソッドの呼び出しを表す式は、これらのメソッドの Queryable の実装を参照します。The expressions that represent calls to the standard query operator methods refer to the Queryable implementations of these methods. 最終的な式ツリーが、IQueryable データ ソースのプロバイダーの CreateQuery<TElement>(Expression) 実装に渡されて、IQueryable 型の実行可能なクエリが作成されます。The final expression tree is passed to the CreateQuery<TElement>(Expression) implementation of the provider of the IQueryable data source to create an executable query of type IQueryable. 結果は、そのクエリ変数を列挙することにより取得されます。The results are obtained by enumerating that query variable.

// Add a using directive for System.Linq.Expressions.  

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" };  

// The IQueryable data to query.  
IQueryable<String> queryableData = companies.AsQueryable<string>();  

// Compose the expression tree that represents the parameter to the predicate.  
ParameterExpression pe = Expression.Parameter(typeof(string), "company");  

// ***** Where(company => (company.ToLower() == "coho winery" || company.Length > 16)) *****  
// Create an expression tree that represents the expression 'company.ToLower() == "coho winery"'.  
Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));  
Expression right = Expression.Constant("coho winery");  
Expression e1 = Expression.Equal(left, right);  

// Create an expression tree that represents the expression 'company.Length > 16'.  
left = Expression.Property(pe, typeof(string).GetProperty("Length"));  
right = Expression.Constant(16, typeof(int));  
Expression e2 = Expression.GreaterThan(left, right);  

// Combine the expression trees to create an expression tree that represents the  
// expression '(company.ToLower() == "coho winery" || company.Length > 16)'.  
Expression predicateBody = Expression.OrElse(e1, e2);  

// Create an expression tree that represents the expression  
// 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'  
MethodCallExpression whereCallExpression = Expression.Call(  
    typeof(Queryable),  
    "Where",  
    new Type[] { queryableData.ElementType },  
    queryableData.Expression,  
    Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));  
// ***** End Where *****  

// ***** OrderBy(company => company) *****  
// Create an expression tree that represents the expression  
// 'whereCallExpression.OrderBy(company => company)'  
MethodCallExpression orderByCallExpression = Expression.Call(  
    typeof(Queryable),  
    "OrderBy",  
    new Type[] { queryableData.ElementType, queryableData.ElementType },  
    whereCallExpression,  
    Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));  
// ***** End OrderBy *****  

// Create an executable query from the expression tree.  
IQueryable<string> results = queryableData.Provider.CreateQuery<string>(orderByCallExpression);  

// Enumerate the results.  
foreach (string company in results)  
    Console.WriteLine(company);  

/*  This code produces the following output:  

    Blue Yonder Airlines  
    City Power & Light  
    Coho Winery  
    Consolidated Messenger  
    Graphic Design Institute  
    Humongous Insurance  
    Lucerne Publishing  
    Northwind Traders  
    The Phone Company  
    Wide World Importers  
*/  

このコードでは、Queryable.Where メソッドに渡される述語で固定数の式を使います。This code uses a fixed number of expressions in the predicate that is passed to the Queryable.Where method. ただし、ユーザー入力に依存する可変個の述語式を結合するアプリケーションを作成することもできます。However, you can write an application that combines a variable number of predicate expressions that depends on the user input. また、ユーザーからの入力に応じて、クエリで呼び出される標準クエリ演算子を変えることもできます。You can also vary the standard query operators that are called in the query, depending on the input from the user.

コードのコンパイルCompiling the Code

  • 新しいコンソール アプリケーション プロジェクトを作成します。Create a new Console Application project.

  • System.Core.dll がまだ参照されていない場合は、参照を追加します。Add a reference to System.Core.dll if it is not already referenced.

  • System.Linq.Expressions 名前空間をインクルードします。Include the System.Linq.Expressions namespace.

  • 例のコードをコピーして、Main メソッドに貼り付けます。Copy the code from the example and paste it into the Main method.

関連項目See Also

式ツリー (C#)Expression Trees (C#)
方法: 式ツリー (c#) を実行How to: Execute Expression Trees (C#)
方法: 実行時に述語フィルターを動的に指定するHow to: Dynamically Specify Predicate Filters at Runtime