Share via


Requêtes dans LINQ to Entities

Une requête est une expression qui récupère des données à partir d'une source de données. En général, les requêtes sont exprimées dans un langage de requête spécialisé, tel que SQL pour les bases de données relationnelles et XQuery pour XML. Par conséquent, les développeurs ont donc dû apprendre un nouveau langage de requête pour chaque type de source de données ou format de données qu'ils interrogent. LINQ (Language-Integrated Query) propose un modèle cohérent plus simple qui permet d'utiliser des données de types de sources et de formats divers. Dans une requête LINQ, vous travaillez toujours avec des objets de programmation.

Une opération de requête LINQ se compose de trois actions : obtenir la ou les sources de données, créer la requête, puis exécuter cette dernière.

Les sources de données qui implémentent l'interface générique IEnumerable ou l'interface générique IQueryable peuvent être interrogées via LINQ. Les instances de la classe générique ObjectQuery, laquelle implémente l'interface générique IQueryable, servent de source de données pour les requêtes LINQ to Entities. La classe générique ObjectQuery représente une requête qui retourne une instance ou une collection d'entités typées. Le développeur construit une instance à partir de la classe ObjectContext, laquelle est la classe principale d'interaction avec un modèle EDM (Modèle de données d'entité) sous forme d'objets CLR.

Dans la requête, vous spécifiez exactement les informations que vous voulez récupérer à partir de la source de données. Une requête peut également spécifier la manière dont ces informations doivent être triées, regroupées et mises en forme avant d'être retournées. Dans LINQ, une requête est stockée dans une variable. Si la requête retourne une séquence de valeurs, la variable de requête doit elle-même être de type requêtable. Cette variable de requête n'effectue aucune action et ne retourne aucune donnée ; elle stocke uniquement les informations de requête. Une fois que vous avez créé une requête, vous devez l'exécuter pour récupérer des données.

Dans une requête qui retourne une séquence de valeurs, la variable de requête elle-même ne contient jamais les résultats de requête et stocke uniquement les commandes de requête. L'exécution de la requête est différée jusqu'à ce que la variable de requête soit parcourue à l'aide d'une boucle foreach ou For Each. C'est ce que l'on appelle une exécution différée. Autrement dit, l'exécution de la requête a lieu un certain laps de temps après sa construction. Vous pouvez ainsi exécuter une requête aussi fréquemment que vous le souhaitez. Cela est utile lorsque, par exemple, l'une de vos bases de données est en cours de mise à jour par d'autres 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.

Contrairement aux requêtes différées qui retournent une séquence de valeurs, les requêtes qui retournent une valeur singleton sont exécutées immédiatement. Les requêtes Count, Max, Average et First en sont quelques exemples. Elles s'exécutent immédiatement parce que les résultats de la requête sont nécessaires pour calculer le résultat singleton. Vous pouvez également utiliser les méthodes ToList ou ToArray sur une requête pour forcer l'exécution immédiate d'une requête qui ne produit pas de valeur singleton. Ces techniques destinées à forcer l'exécution immédiate d'une requête peuvent être utiles lorsque vous souhaitez mettre en cache les résultats d'une requête. Pour plus d'informations sur l'exécution de requêtes différées et immédiates, voir Introduction à LINQ.

Requêtes

Les requêtes LINQ to Entities peuvent être composées dans deux syntaxes différentes : la syntaxe d'expression de requête et la syntaxe de requête fondée sur une méthode. La syntaxe d'expression de requête est une caractéristique nouvelle dans C# 3.0 et Visual Basic 9.0. Elle est constituée d'un ensemble de clauses écrites dans une syntaxe déclarative similaire à Transact-SQL ou XQuery. Toutefois, le Common Language Runtime (CLR) du .NET Framework ne peut pas lire la syntaxe d'expression de requête proprement dite. Par conséquent, au moment de la compilation, les expressions de requête sont traduites en appels de méthodes pour que le CLR puisse les comprendre. Ces méthodes sont appelées opérateurs de requête standard. En tant que développeur, vous pouvez les appeler directement en utilisant la syntaxe de méthode plutôt que la syntaxe de requête. Pour plus d'informations, voir Comparaison de la syntaxe de requête et de la syntaxe de méthode (LINQ). Pour plus d'informations sur l'utilisation des opérateurs de requête standard, voir Guide de programmation général LINQ.

Syntaxe d'expression de requête

Les expressions de requête utilisent une syntaxe de requête déclarative. Cette syntaxe permet au développeur d'écrire des requêtes dans un langage de haut niveau formaté de façon similaire à Transact-SQL. En utilisant la syntaxe d'expression de requête, vous pouvez même effectuer des opérations de filtrage, de classement et de regroupement complexes sur des sources de données avec un minimum de code. Pour plus d'informations, voir Expressions de requête LINQ (Guide de programmation C#) et Opérations de requête de base (Visual Basic).

L'exemple suivant utilise Select pour retourner toutes les lignes de Product et afficher les noms de produits.

Using AWEntities As New AdventureWorksEntities
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productNames = _
       From p In products _
       Select p.Name

    Console.WriteLine("Product Names:")
    For Each productName In productNames
        Console.WriteLine(productName)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<string> productNames =
       from p in products
       select p.Name;

    Console.WriteLine("Product Names:");
    foreach (var productName in productNames)
    {
        Console.WriteLine(productName);
    }
}

Syntaxe de requête fondée sur une méthode

Une autre manière de composer des requêtes LINQ to Entities consiste à utiliser des requêtes fondées sur une méthode. La syntaxe de requête fondée sur une méthode est une séquence d'appels directs de méthodes d'opérateur LINQ passant des expressions lambda comme paramètres. Pour plus d'informations, voir Expressions lambda (Guide de programmation C#).

Cet exemple utilise Select pour retourner toutes les lignes de Product et afficher les noms de produits.

Using AWEntities As New AdventureWorksEntities


    Dim productNames = AWEntities.Product.Select(Function(p) p.Name)


    Console.WriteLine("Product Names:")
    For Each productName In productNames
        Console.WriteLine(productName)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<string> productNames = products.Select(p => p.Name);


    Console.WriteLine("Product Names:");
    foreach (var productName in productNames)
    {
        Console.WriteLine(productName);
    }
}

Composition de requêtes

Comme mentionné précédemment dans cette rubrique, la variable de requête elle-même ne stocke les commandes de requête que lorsque la requête est conçue pour retourner une séquence de valeurs. Si la requête ne contient pas de méthode qui déclenche une exécution immédiate, l'exécution effective de la requête est différée jusqu'à ce que vous parcouriez la variable de requête dans une boucle foreach ou For Each. L'exécution différée permet de combiner plusieurs requêtes ou d'étendre une requête. 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 ces modifications. Dans l'exemple suivant, la première requête retourne tous les produits. La deuxième requête étend la première en utilisant Where pour retourner tous les produits de taille « L » :

Using AWEntities As New AdventureWorksEntities()
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productsQuery = _
        From p In 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
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{

    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<Product> productsQuery =
        from p in 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);
    }
}

Une fois qu'une requête est exécutée, toutes les requêtes suivantes utilisent les opérateurs LINQ en mémoire. 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. Ces opérateurs de conversion sont notamment : ToList, ToArray, ToLookup et ToDictionary.

Dans l'exemple suivant, la première requête retourne tous les produits. La deuxième requête étend la première une fois qu'elle a été exécutée pour retourner les produits de couleur rouge.

Using AWEntities As New AdventureWorksEntities()
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productsQuery = _
        From p In products _
        Select p

    Console.WriteLine("The list of products:")
    For Each Product As Product In productsQuery
        Console.WriteLine(Product.Name)
    Next

    Dim redProducts = productsQuery _
        .Where(Function(p) p.Color = "Red") _
        .Select(Function(p) p)

    Console.WriteLine("")
    Console.WriteLine("The list of red products:")
    For Each redProduct As Product In redProducts
        Console.WriteLine(redProduct.Name)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{

    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<Product> productsQuery =
        from p in products
        select p;

    Console.WriteLine("The list of products:");
    foreach (Product product in productsQuery)
    {
        Console.WriteLine(product.Name);
    }

    IQueryable<Product> redProducts = productsQuery
        .Where(p => p.Color == "Red")
        .Select(p => p);

    Console.WriteLine("");
    Console.WriteLine("The list of red products:");
    foreach (Product redProduct in redProducts)
    {
        Console.WriteLine(redProduct.Name);
    }

}

Voir aussi

Autres ressources

LINQ to Entities
Mise en route de LINQ en C#
Mise en route de LINQ dans Visual Basic