クエリの実行Query Execution

ユーザーによって作成された LINQ クエリは、コマンド ツリーに変換されます。After a LINQ query is created by a user, it is converted to a command tree. コマンド ツリーは、Entity Framework と互換性のあるクエリの表現です。A command tree is a representation of a query that is compatible with the Entity Framework. コマンド ツリーは、その後データ ソースに対して実行されます。The command tree is then executed against the data source. クエリの実行時には、すべてのクエリ式 (つまりクエリの全コンポーネント) が評価されます。これには結果の具体化で使用される式も含まれます。At query execution time, all query expressions (that is, all components of the query) are evaluated, including those expressions that are used in result materialization.

クエリ式が評価されるタイミングはさまざまです。At what point query expressions are executed can vary. LINQ クエリは、クエリ変数の作成時ではなく、常にクエリ変数の反復処理時に実行されます。LINQ queries are always executed when the query variable is iterated over, not when the query variable is created. これは呼び出されます遅延実行します。This is called deferred execution. クエリを即時に実行することもできます。これは、クエリの結果をキャッシュする場合に有効です。You can also force a query to execute immediately, which is useful for caching query results. このことについては、このトピックの後半で説明します。This is described later in this topic.

LINQ to Entities クエリを実行すると、クエリ内の一部の式がサーバー上で実行され、別の一部の式がクライアント上でローカルに実行される場合があります。When a LINQ to Entities query is executed, some expressions in the query might be executed on the server and some parts might be executed locally on the client. クライアント側での式の評価は、サーバー上でクエリが実行される前に行われます。Client-side evaluation of an expression takes place before the query is executed on the server. 式がクライアント上で評価される場合、クエリ内の式がその評価の結果に置き換えられた後、サーバー上でクエリが実行されます。If an expression is evaluated on the client, the result of that evaluation is substituted for the expression in the query, and the query is then executed on the server. クエリはデータ ソースに対して実行されるため、クライアントで指定された動作よりもデータ ソースの構成がオーバーライドされます。Because queries are executed on the data source, the data source configuration overrides the behavior specified in the client. たとえば、Null 値の処理方法や、数値の有効桁数などはサーバーの設定によって異なります。For example, null value handling and numerical precision depend on the server settings. クエリの実行中にサーバーに対してスローされた例外は、クライアントに直接渡されます。Any exceptions thrown during query execution on the server are passed directly up to the client.

ヒント

オペレーターの実行動作をすばやく特定することができます、表形式クエリ演算子の便利な概要については、次を参照してください。分類の標準クエリ演算子の実行の方法で (C#)します。For a convenient summary of query operators in table format, which lets you quickly identify an operator's execution behavior, see Classification of Standard Query Operators by Manner of Execution (C#).

クエリの遅延実行Deferred query execution

一連の値を返すクエリでは、クエリ変数そのものはクエリ結果を保持しません。クエリ変数には、クエリのコマンドが格納されるだけです。In a query that returns a sequence of values, the query variable itself never holds the query results and only stores the query commands. クエリ変数が foreach ループまたは For Each ループで反復処理されるまで、クエリは実行されません。Execution of the query is deferred until the query variable is iterated over in a foreach or For Each loop. 呼ばれます遅延実行; は、クエリが実行が作成された、クエリは、しばらく時間が発生します。This is known as deferred execution; that is, query execution occurs some time after the query is constructed. これは、任意のタイミングでクエリを実行できるということを意味します。This means that you can execute a query as frequently as you want to. これは、たとえば他のアプリケーションによって更新されるデータベースがある場合に便利です。This is useful when, for example, you have a database that is being updated by other applications. アプリケーションで、最新情報を取得するクエリを作成し、それを繰り返し実行することにより、更新のたびに最新の情報を取得できます。In your application, you can create a query to retrieve the latest information and repeatedly execute the query, returning the updated information every time.

遅延実行により、複数のクエリを組み合わせたり、クエリを拡張したりすることが可能となります。Deferred execution enables multiple queries to be combined or a query to be extended. クエリを拡張して新しい操作を追加すると、その変更が最終的な実行時に反映されます。When a query is extended, it is modified to include the new operations, and the eventual execution will reflect the changes. 次の例の最初のクエリでは、すべての製品が返されます。In the following example, the first query returns all the products. 2 つ目のクエリでは、サイズが "L" のすべての製品を返すように、Where を使って 1 つ目のクエリを拡張しています。The second query extends the first by using Where to return all the products of size "L":

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    IQueryable<Product> productsQuery =
        from p in context.Products
        select p;

    IQueryable<Product> largeProducts = productsQuery.Where(p => p.Size == "L");

    Console.WriteLine("Products of size 'L':");
    foreach (var product in largeProducts)
    {
        Console.WriteLine(product.Name);
    }
}
Using context As New AdventureWorksEntities()
    Dim productsQuery = _
        From p In context.Products _
        Select p

    Dim largeProducts = _
        productsQuery.Where(Function(p) p.Size = "L")

    Console.WriteLine("Products of size 'L':")
    For Each product In largeProducts
        Console.WriteLine(product.Name)
    Next
End Using

クエリが実行された後、後続のすべてのクエリでメモリ内の LINQ 演算子が使用されます。After a query has been executed all successive queries will use the in-memory LINQ operators. foreach ステートメントや For Each ステートメントを使用することによって、または LINQ 変換演算子の 1 つを呼び出すことによって、クエリ変数を反復処理すると、即時実行が発生します。Iterating over the query variable by using a foreach or For Each statement or by calling one of the LINQ conversion operators will cause immediate execution. これらの変換演算子には、ToListToArrayToLookupToDictionary などがあります。These conversion operators include the following: ToList, ToArray, ToLookup, and ToDictionary.

クエリの即時実行Immediate Query Execution

一連の値を生成するクエリの遅延実行とは対照的に、シングルトン値を返すクエリは直ちに実行されます。In contrast to the deferred execution of queries that produce a sequence of values, queries that return a singleton value are executed immediately. シングルトン クエリの例としては、AverageCountFirstMax があります。Some examples of singleton queries are Average, Count, First, and Max. これらのシングルトン クエリは、結果を計算するためにはシーケンスを生成する必要があるため、直ちに実行されます。These execute immediately because the query must produce a sequence to calculate the singleton result. 即時実行は強制することもできます。You can also force immediate execution. これはクエリの結果をキャッシュする場合などに便利です。This is useful when you want to cache the results of a query. クエリまたはクエリ変数で ToList メソッド、ToDictionary メソッド、または ToArray メソッドを呼び出すと、シングルトン値を生成しないクエリの即時実行を強制できます。To force immediate execution of a query that does not produce a singleton value, you can call the ToList method, the ToDictionary method, or the ToArray method on a query or query variable. 次の例では、ToArray メソッドを使用して、シーケンスを配列として即時評価します。The following example uses the ToArray method to immediately evaluate a sequence into an array.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    ObjectSet<Product> products = context.Products;

    Product[] prodArray = (
        from product in products
        orderby product.ListPrice descending
        select product).ToArray();

    Console.WriteLine("Every price from highest to lowest:");
    foreach (Product product in prodArray)
    {
        Console.WriteLine(product.ListPrice);
    }
}
Using context As New AdventureWorksEntities
    Dim products As ObjectSet(Of Product) = context.Products

    Dim prodArray As Product() = ( _
        From product In products _
        Order By product.ListPrice Descending _
        Select product).ToArray()

    Console.WriteLine("The list price from highest to lowest:")
    For Each prod As Product In prodArray
        Console.WriteLine(prod.ListPrice)
    Next
End Using

また、foreach ループまたは For Each ループをクエリ式の直後に配置して実行を強制することも、ToList または ToArray を呼び出すことにより、単一のコレクション オブジェクト内のすべてのデータをキャッシュすることにより、実行を強制することもできます。You could also force execution by putting the foreach or For Each loop immediately after the query expression, but by calling ToList or ToArray you cache all the data in a single collection object.

ストア実行Store Execution

一般的に、LINQ to Entities の式はサーバー上で評価されるため、式の動作がデータ ソースのセマンティクスではなく、共通言語ランタイム (CLR) セマンティクスに従っているとは限りません。In general, expressions in LINQ to Entities are evaluated on the server, and the behavior of the expression should not be expected to follow common language runtime (CLR) semantics, but those of the data source. ただし、これには式がクライアント上で実行された場合などの例外があります。There are exceptions to this, however, such as when the expression is executed on the client. これは、サーバーとクライアントが異なるタイム ゾーンに存在する場合など、予期しない結果をもたらすことがあります。This could cause unexpected results, for example when the server and client are in different time zones.

クエリ内の一部の式はクライアント上で実行される場合があります。Some expressions in the query might be executed on the client. 通常、ほとんどのクエリ実行はサーバーで発生するものと見なされます。In general, most query execution is expected to occur on the server. データ ソースにマップされたクエリ要素に対して実行されたメソッドの他に、クエリにはローカルで実行できる式が含まれる場合がよくあります。Aside from methods executed against query elements mapped to the data source, there are often expressions in the query that can be executed locally. クエリ式のローカルでの実行では、クエリ実行または結果の作成で使用できる値が生成されます。Local execution of a query expression yields a value that can be used in the query execution or result construction.

値のバインド、サブ式、終了からのサブクエリ、およびクエリ結果へのオブジェクトの具体化などの特定の操作は、常にクライアントで実行されます。Certain operations are always executed on the client, such as binding of values, sub expressions, sub queries from closures, and materialization of objects into query results. その最終的な結果として、これらの要素 (パラメーター値など) は実行中には更新できなくなります。The net effect of this is that these elements (for example, parameter values) cannot be updated during the execution. 匿名型は、データ ソースでインラインで作成できますが、必ずしもそれを想定することはできません。Anonymous types can be constructed inline on the data source, but should not be assumed to do so. インラインのグループはデータ ソースでも作成できますが、すべてのインスタンスでそれが可能であると見なすことはできません。Inline groupings can be constructed in the data source, as well, but this should not be assumed in every instance. 通常、サーバー上で何を作成できるかについて想定しないことが賢明です。In general, it is best not to make any assumptions about what is constructed on the server.

このセクションでは、コードをクライアント上でローカルに実行するシナリオについて説明します。This section describes the scenarios in which code is executed locally on the client. どの種類の式がローカルで実行する詳細については、次を参照してください。 LINQ to Entities クエリ内の式します。For more information about which types of expressions are executed locally, see Expressions in LINQ to Entities Queries.

リテラルとパラメーターLiterals and Parameters

次の例に示した orderID 変数などのローカル変数は、クライアントで評価されます。Local variables, such as the orderID variable in the following example, are evaluated on the client.

int orderID = 51987;

IQueryable<SalesOrderHeader> salesInfo =
    from s in context.SalesOrderHeaders
    where s.SalesOrderID == orderID
    select s;
Dim orderID As Integer = 51987

Dim salesInfo = _
    From s In context.SalesOrderHeaders _
    Where s.SalesOrderID = orderID _
    Select s

メソッド パラメーターもクライアントで評価されます。Method parameters are also evaluated on the client. 下の orderID メソッドに渡される MethodParameterExample パラメーターがその例です。The orderID parameter passed into the MethodParameterExample method, below, is an example.

public static void MethodParameterExample(int orderID)
{
    using (AdventureWorksEntities context = new AdventureWorksEntities())
    {
        
        IQueryable<SalesOrderHeader> salesInfo =
            from s in context.SalesOrderHeaders
            where s.SalesOrderID == orderID
            select s;                

        foreach (SalesOrderHeader sale in salesInfo)
        {
            Console.WriteLine("OrderID: {0}, Total due: {1}", sale.SalesOrderID, sale.TotalDue);
        }
    }
}
Function MethodParameterExample(ByVal orderID As Integer)
    Using context As New AdventureWorksEntities()

        Dim salesInfo = _
            From s In context.SalesOrderHeaders _
            Where s.SalesOrderID = orderID _
            Select s

        Console.WriteLine("Sales order info:")
        For Each sale As SalesOrderHeader In salesInfo
            Console.WriteLine("OrderID: {0}, Total due: {1}", sale.SalesOrderID, sale.TotalDue)
        Next
    End Using

End Function

クライアントでのリテラルのキャストCasting Literals on the Client

null から CLR 型へのキャストは、次のようにクライアントで実行されます。Casting from null to a CLR type is executed on the client:

IQueryable<Contact> query =
    from c in context.Contacts
    where c.EmailAddress == (string)null
    select c;
Dim query = _
    From c In context.Contacts _
    Where c.EmailAddress = CType(Nothing, String) _
    Select c

Null 値が許容される Decimal などの型へのキャストは、次のようにクライアントで実行されます。Casting to a type, such as a nullable Decimal, is executed on the client:

var weight = (decimal?)23.77;
IQueryable<Product> query =
    from product in context.Products
    where product.Weight == weight
    select product;
Dim weight = CType(23.77, Decimal?)
Dim query = _
    From product In context.Products _
        Where product.Weight = weight _
        Select product

リテラルのコンストラクターConstructors for Literals

概念モデル型にマップできる新しい CLR 型は、次のようにクライアントで実行されます。New CLR types that can be mapped to conceptual model types are executed on the client:

var weight = new decimal(23.77);
IQueryable<Product> query =
    from product in context.Products
    where product.Weight == weight
    select product;
Dim weight = New Decimal(23.77)
Dim query = _
    From product In context.Products _
    Where product.Weight = weight _
    Select product

新しい配列もクライアントで実行されます。New arrays are also executed on the client.

ストアの例外Store Exceptions

クエリ実行時に発生したストア エラーはすべてクライアントに渡され、マッピングも処理もされません。Any store errors that are encountered during query execution are passed up to the client, and are not mapped or handled.

ストアの構成Store Configuration

ストアでクエリが実行される場合、ストアの構成はすべてのクライアント動作をオーバーライドし、ストア セマンティクスはすべての演算および式で表現されます。When the query executes on the store, the store configuration overrides all client behaviors, and store semantics are expressed for all operations and expressions. これにより、Null 比較、GUID 順序付け、precise 以外のデータ型 (浮動小数点型や DateTime など) を含む演算の精度や正確性、および文字列型演算などの領域において、CLR とストアの実行間で違いが発生する可能性があります。This can result in a difference in behavior between CLR and store execution in areas such as null comparisons, GUID ordering, precision and accuracy of operations involving non-precise data types (such as floating point types or DateTime), and string operations. クエリ結果を調べる場合にはこのことに留意することが重要です。It is important to keep this in mind when examining query results.

CLR および SQL Server 間での動作の違いの例を次に示します。For example, the following are some differences in behavior between the CLR and SQL Server:

  • SQL Server は CLR とは異なる方法で GUID を順序付けます。SQL Server orders GUIDs differently than the CLR.

  • SQL Server で Decimal 型を扱う場合は、結果の精度でも差違が発生する場合もあります。There can also be differences in result precision when dealing with the Decimal type on SQL Server. これは、SQL Server の decimal 型の固定有効桁数の要件によります。This is due to the fixed precision requirements of the SQL Server decimal type. たとえば、Decimal 値 0.0、0.0、および 1.0 の平均は、クライアント上のメモリでは 0.3333333333333333333333333333 ですが、ストアでは 0.333333 です (SQL Server の decimal 型の既定の有効桁数に基づきます)。For example, the average of Decimal values 0.0, 0.0, and 1.0 is 0.3333333333333333333333333333 in memory on the client, but 0.333333 in the store (based on the default precision for SQL Server’s decimal type).

  • SQL Server では、一部の文字列比較演算も CLR とは異なった方法で処理されます。Some string comparison operations are also handled differently in SQL Server than in the CLR. 文字列比較の動作は、サーバー上の照合順序の設定によって異なります。String comparison behavior depends on the collation settings on the server.

  • LINQ to Entities クエリに含まれる関数呼び出しまたはメソッド呼び出しは、Entity Framework の正規関数にマップされ、その後 Transact-SQL に変換され、SQL Server データベースで実行されます。Function or method calls, when included in a LINQ to Entities query, are mapped to canonical functions in the Entity Framework, which are then translated to Transact-SQL and executed on the SQL Server database. マップされたこれらの関数が表す動作は、基本クラス ライブラリでの実装とは異なる場合もあります。There are cases when the behavior these mapped functions exhibit might differ from the implementation in the base class libraries. たとえば、空の文字列をパラメーターとして Contains, StartsWith メソッドおよび EndsWith メソッドを呼び出すと、CLR での実行では true が返されますが、SQL Server での実行では false が返されます。For example, calling the Contains, StartsWith, and EndsWith methods with an empty string as a parameter will return true when executed in the CLR, but will return false when executed in SQL Server. また、末尾の空白のみが異なる 2 つの文字列は SQL Server では同じと見なされますが、CLR では同じではないと見なされるため、EndsWith メソッドは、異なる結果を返す場合があります。The EndsWith method can also return different results because SQL Server considers two strings to be equal if they only differ in trailing white space, whereas the CLR considers them to be not equal. この例を次に示します。This is illustrated by the following example:

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    IQueryable<string> query = from p in context.Products
                               where p.Name == "Reflector"
                               select p.Name;

    IEnumerable<bool> q = query.Select(c => c.EndsWith("Reflector "));

    Console.WriteLine("LINQ to Entities returns: " + q.First());
    Console.WriteLine("CLR returns: " + "Reflector".EndsWith("Reflector "));

}
Using context As New AdventureWorksEntities()

    Dim query = _
        From p In context.Products _
        Where p.Name = "Reflector" _
        Select p.Name

    Dim q = _
        query.Select(Function(c) c.EndsWith("Reflector "))

    Console.WriteLine("LINQ to Entities returns: " & q.First())
    Console.WriteLine("CLR returns: " & "Reflector".EndsWith("Reflector "))
End Using