Exécution de la requêteQuery Execution

Après avoir été créée par un utilisateur, une requête LINQ est convertie en arborescence de commandes.After a LINQ query is created by a user, it is converted to a command tree. Une arborescence de commandes est une représentation de requête compatible avec Entity Framework.A command tree is a representation of a query that is compatible with the Entity Framework. L’arborescence de requêtes est ensuite exécutée sur la source de données.The command tree is then executed against the data source. Pendant l'exécution de la requête, toutes les expressions de la requête (c'est-à-dire, toutes ses composantes) sont évaluées, y compris les expressions utilisées dans la matérialisation des résultats.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.

Le moment où les expressions d'une requête sont exécutées peut varier.At what point query expressions are executed can vary. Les requêtes LINQ sont toujours exécutées lorsque la variable de requête fait l'objet d'une itération, et non au moment où elle est créée.LINQ queries are always executed when the query variable is iterated over, not when the query variable is created. Il s’agit exécution différée.This is called deferred execution. Vous pouvez également forcer l'exécution immédiate de la requête, ce qui est utile pour mettre en cache les résultats de la requête.You can also force a query to execute immediately, which is useful for caching query results. Ce sujet est abordé plus loin dans cette rubrique.This is described later in this topic.

Lorsqu'une requête LINQ to Entities est exécutée, il est possible que certaines expressions de la requête soient exécutées sur le serveur et que certaines parties soient exécutées localement sur le client.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. L'évaluation côté client d'une expression a lieu avant l'exécution de la requête sur le serveur.Client-side evaluation of an expression takes place before the query is executed on the server. Si une expression est évaluée sur le client, le résultat de cette évaluation remplace l'expression de la requête, et la requête est ensuite exécutée sur le serveur.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. Étant donné que les requêtes sont exécutées sur la source de données, la configuration de la source de données prévaut sur le comportement spécifié dans le client.Because queries are executed on the data source, the data source configuration overrides the behavior specified in the client. Par exemple, la gestion des valeurs Null et la précision numérique dépendent des paramètres du serveur.For example, null value handling and numerical precision depend on the server settings. Toutes les exceptions levées pendant l'exécution de la requête sur le serveur sont passées directement au client.Any exceptions thrown during query execution on the server are passed directly up to the client.

Conseil

Pour obtenir un résumé pratique d’opérateurs de requête au format de table, ce qui vous permet d’identifier rapidement le comportement de l’exécution d’un opérateur, consultez Classification des opérateurs de requête Standard en mode d’exécution (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#).

Exécution de requête différéeDeferred query execution

Dans une requête qui retourne une séquence, la variable de requête elle-même ne contient jamais les résultats de la requête et stocke uniquement les commandes de requête.In a query that returns a sequence of values, the query variable itself never holds the query results and only stores the query commands. L'exécution de la requête est différée jusqu'à ce que la variable de requête soit itérée au sein d'une boucle foreach ou For Each.Execution of the query is deferred until the query variable is iterated over in a foreach or For Each loop. Il s’agit exécution différée; autrement dit, la requête exécution lieu un certain temps après la construction de la requête.This is known as deferred execution; that is, query execution occurs some time after the query is constructed. Vous pouvez ainsi exécuter une requête aussi fréquemment que vous le souhaitez.This means that you can execute a query as frequently as you want to. Cela est utile lorsque, par exemple, l'une de vos bases de données est en cours de mise à jour par d'autres applications.This is useful when, for example, you have a database that is being updated by other applications. Dans votre application, vous pouvez créer une requête pour récupérer les informations les plus récentes et l'exécuter à plusieurs reprises, pour retourner chaque fois les informations à jour.In your application, you can create a query to retrieve the latest information and repeatedly execute the query, returning the updated information every time.

L'exécution différée permet de combiner plusieurs requêtes ou d'étendre une requête.Deferred execution enables multiple queries to be combined or a query to be extended. Lorsqu'une requête est étendue, elle est modifiée de manière à inclure les nouvelles opérations, et l'exécution finale reflète les modifications.When a query is extended, it is modified to include the new operations, and the eventual execution will reflect the changes. Dans l'exemple suivant, la première requête retourne tous les produits.In the following example, the first query returns all the products. La deuxième requête étend la première en utilisant Where pour retourner tous les produits de taille « L » :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

Une fois qu'une requête est exécutée, toutes les requêtes suivantes utilisent les opérateurs LINQ en mémoire.After a query has been executed all successive queries will use the in-memory LINQ operators. L'itération sur la variable de requête par le biais d'une instruction foreach ou For Each ou par l'appel à l'un des opérateurs de conversion LINQ provoqueront une exécution immédiate.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. Ces opérateurs de conversion sont notamment : ToList, ToArray, ToLookup et ToDictionary.These conversion operators include the following: ToList, ToArray, ToLookup, and ToDictionary.

Exécution de requête immédiateImmediate Query Execution

Contrairement à l'exécution différée des requêtes qui produisent une séquence de valeurs, les requêtes qui retournent une valeur singleton sont exécutées immédiatement.In contrast to the deferred execution of queries that produce a sequence of values, queries that return a singleton value are executed immediately. Les requêtes Average, Count, First et Max en sont quelques exemples.Some examples of singleton queries are Average, Count, First, and Max. Elles s'exécutent immédiatement parce que la requête doit produire une séquence pour calculer le résultat singleton.These execute immediately because the query must produce a sequence to calculate the singleton result. Vous pouvez également forcer l'exécution immédiate.You can also force immediate execution. Cela peut s'avérer utile lorsque vous souhaitez mettre en cache les résultats d'une requête.This is useful when you want to cache the results of a query. Pour forcer l'exécution immédiate d'une requête qui ne produit pas de valeur singleton, vous pouvez appeler la méthode ToList, ToDictionary ou ToArray sur une requête ou une variable de requête.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. L'exemple ci-dessous utilise la méthode ToArray pour évaluer immédiatement une séquence dans un tableau.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

Vous pouvez également forcer l’exécution en plaçant la boucle foreach ou For Each de suite après l’expression de requête, mais en appelant ToList ou ToArray, vous mettez en cache toutes les données contenues dans un objet de collection unique.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.

Exécution sur les magasinsStore Execution

En règle générale, les expressions dans LINQ to Entities sont évaluées sur le serveur, et le comportement de l'expression n'est pas censé suivre la sémantique CLR (Common Language Runtime), mais celle de la source de données.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. Toutefois, il y a des exceptions à cette règle, notamment lorsque l'expression est exécutée sur le client.There are exceptions to this, however, such as when the expression is executed on the client. Cela peut donner lieu à des résultats inattendus, par exemple lorsque le serveur et le client sont situés dans des fuseaux horaires différents.This could cause unexpected results, for example when the server and client are in different time zones.

Il est possible que certaines expressions de la requête soient exécutées sur le client.Some expressions in the query might be executed on the client. En général, l'exécution de la requête est supposée se produire en grande partie sur le serveur.In general, most query execution is expected to occur on the server. En dehors des méthodes exécutées sur des éléments de requête mappés à la source de données, il existe souvent, dans la requête, des expressions qui peuvent être exécutées localement.Aside from methods executed against query elements mapped to the data source, there are often expressions in the query that can be executed locally. L'exécution locale d'une expression de requête génère une valeur qui peut être utilisée dans l'exécution de la requête ou dans la construction du résultat.Local execution of a query expression yields a value that can be used in the query execution or result construction.

Certaines opérations sont toujours exécutées sur le client, notamment la liaison de valeurs, les sous-expressions, les sous-requêtes de clôtures et la matérialisation d'objets dans les résultats de requête.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. En conséquence de quoi, ces éléments (par exemple, les valeurs de paramètres) ne peuvent pas être mis à jour pendant l'exécution.The net effect of this is that these elements (for example, parameter values) cannot be updated during the execution. Des types anonymes peuvent être construits par incorporation dans la source de données, mais ils ne sont pas censés l'être.Anonymous types can be constructed inline on the data source, but should not be assumed to do so. Des regroupements inline peuvent être construits dans la source de données, mais cela n'est pas systématique.Inline groupings can be constructed in the data source, as well, but this should not be assumed in every instance. En règle générale, il est préférable de ne pas faire de suppositions sur ce qui est construit sur le serveur.In general, it is best not to make any assumptions about what is constructed on the server.

Cette section décrit les scénarios dans lesquels le code est exécuté localement sur le client.This section describes the scenarios in which code is executed locally on the client. Pour plus d’informations sur les types d’expressions sont exécutées localement, consultez Expressions dans les requêtes LINQ to Entities.For more information about which types of expressions are executed locally, see Expressions in LINQ to Entities Queries.

Littéraux et paramètresLiterals and Parameters

Les variables locales, telles que la variable orderID de l'exemple suivant, sont évaluées sur le client.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

Les paramètres de méthode sont également évalués sur le client.Method parameters are also evaluated on the client. Le paramètre orderID passé dans la méthode MethodParameterExample ci-dessous en est l'illustration.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

Conversion des littéraux sur le clientCasting Literals on the Client

Le cast d'une valeur null en type CLR est exécutée sur le client :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

Le cast en type, tel qu'un type Decimal Nullable, est exécutée sur le client :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

Constructeurs pour littérauxConstructors for Literals

Les nouveaux types CLR qui peuvent être mappés aux types de modèle conceptuel sont exécutés sur le client :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

Les nouveaux tableaux sont également exécutés sur le client.New arrays are also executed on the client.

Exceptions de magasinStore Exceptions

Les erreurs de magasin rencontrées lors de l'exécution d'une requête sont transmises au client. Elles ne sont ni mappées, ni gérées.Any store errors that are encountered during query execution are passed up to the client, and are not mapped or handled.

Configuration de magasinStore Configuration

Lorsque la requête s'exécute sur le magasin, la configuration de ce dernier prévaut sur tous les comportements du client, et la sémantique du magasin est exprimée pour l'ensemble des opérations et des expressions.When the query executes on the store, the store configuration overrides all client behaviors, and store semantics are expressed for all operations and expressions. Il peut en résulter une différence de comportement entre le CLR et l'exécution sur le magasin dans certains domaines tels que les comparaisons de valeurs Null, le tri de GUID, la précision et l'exactitude des opérations faisant intervenir des types de données non précis (par exemple, les types à virgule flottante ou DateTime) et les opérations de chaîne.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. Il est important de garder cela à l'esprit au moment d'examiner des résultats de requête.It is important to keep this in mind when examining query results.

Par exemple, voici quelques différences de comportement entre le CLR et SQL Server :For example, the following are some differences in behavior between the CLR and SQL Server:

  • SQL Server trie les GUID de façon différente par rapport au CLR.SQL Server orders GUIDs differently than the CLR.

  • Des différences peuvent également être constatées sur le plan de la précision des résultats lorsque le type Décimal est utilisé dans SQL Server.There can also be differences in result precision when dealing with the Decimal type on SQL Server. Cela est dû aux exigences de précision fixe inhérentes au type Décimal de SQL Server.This is due to the fixed precision requirements of the SQL Server decimal type. Par exemple, la moyenne des valeurs Decimal 0,0, 0,0 et 1,0 est de 0,3333333333333333333333333333 dans la mémoire du client, mais de 0,333333 dans le magasin (selon la précision par défaut du type Décimal de SQL Server).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).

  • De même, le traitement de certaines opérations de comparaison de chaînes est différent selon qu'elles sont traitées dans SQL Server ou dans le CLR.Some string comparison operations are also handled differently in SQL Server than in the CLR. Le comportement en matière de comparaison de chaînes dépend des paramètres de classement du serveur.String comparison behavior depends on the collation settings on the server.

  • Les appels de fonction ou de méthode éventuellement inclus dans une requête LINQ to Entities sont mappés aux fonctions canoniques d'Entity Framework, qui sont ensuite traduites dans Transact-SQL et exécutées sur la base de données 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. Dans certains cas, le comportement affiché par ces fonctions mappées peut être différent de l'implémentation dans les bibliothèques de classes de base.There are cases when the behavior these mapped functions exhibit might differ from the implementation in the base class libraries. Par exemple, l'appel des méthodes Contains, StartsWith et EndsWith avec une chaîne vide en guise de paramètre retourne une valeur true en cas d'exécution dans le CLR, mais retourne une valeur false en cas d'exécution dans SQL Server.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. La méthode EndsWith peut également retourner des résultats différents. En effet, SQL Server considère que deux chaînes sont égales si seul un espace à droite les différencie. Or, dans ce cas, le CLR les considère différentes.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. Ceci est illustré dans l'exemple suivant :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