.jpg)
L’article ci-dessous est la traduction de l’article de Scott Guthrie.
Par Fabien Lavocat, International Program Manager Visual Studio, formateur au laboratoire .NET à l’école supérieure d’informatique SUPINFO.
Note de l’auteur : Cet article est rédigé pour Visual Studio 2008 Bêta 2 - .NET Framework 3.5 Bêta 2. [Version RTM] Les lignes en rouge comme celles-ci, correspondent aux mises à jour pour la version RTM de Visual Studio 2008 et du .NET Framework 3.5.
Le mois dernier, j’ai commencé cette série d’articles sur LINQ to SQL. LINQ to SQL est un Framework O/RM (Object Relational Mapping) intégré dans le .NET Framework 3.5, et qui vous permet de modéliser facilement des bases de données relationnelles en utilisant des classes .NET. Vous pouvez utiliser les expressions LINQ pour requêter la base de données avec elles, mais également mettre à jour/insérer/supprimer des données depuis celle-ci.
Ci-dessous, vous trouverez les deux premières parties de ma série LINQ to SQL :
Dans l’article d’aujourd’hui, nous allons entrer dans les détails sur comment utiliser le modèle de données que nous avons créé dans la partie 2, et montrer comment l’utiliser pour récupérer des données dans un projet ASP .NET.
Dans la partie 2 de cette série, j’ai montré comment créer un modèle de classe LINQ to SQL en utilisant le designer LINQ to SQL inclus dans VS 2008. Ci-dessous vous trouverez le modèle de classe que nous avons créé avec l’exemple de base de données Northwind :
.jpg)
Une fois que vous avez défini vos classes du modèle de données ci-dessus, vous pouvez facilement requêter et récupérer des données de votre base de données. LINQ to SQL vous permet de le faire en écrivant des requêtes avec la syntaxe LINQ avec la classe NorthwindDataContext que nous avons créé en utilisant le designer LINQ to SQL ci-dessus.
Par exemple, pour récupérer et itérer sur une séquence d’objets de type Product, je pourrais écrire le code ci-dessous :
.jpg)
Dans la requête ci-dessus j’ai utilisé la clause « where » dans la requête à la syntaxe LINQ pour retourner seulement les produits d’une catégorie spécifique. J’utilise la propriété CategoryID du Product pour appliquer le filtre.
Une des choses agréable de LINQ to SQL est que j’ai une grande flexibilité sur la façon d’interroger mes données, et je peux tirer partie des associations que j’ai mis en place lors de la modélisation de mes classes de données LINQ to SQL pour traiter des requêtes riches et plus naturelles sur la base de données. Par exemple, je pourrais modifier la requête pour filtrer par CategoryName du produit au lieu de CategoryID en écrivant ma requête LINQ comme cela :
.jpg)
Notez ci-dessus comment j’ai utilisé la propriété « Category » qui est dans chaque objet Product pour filtrer par CategoryName de la catégorie à laquelle le produit appartient. Cette propriété a automatiquement été créée pour nous par LINQ to SQL parce que nous avons modélisé les classes Category et Product comme aillant une relation une-à-plusieurs entre eux dans la base de données.
Un autre simple exemple l’utilisation de vos relations du modèle de données avec des requêtes, nous pouvons écrire la requête LINQ ci-dessous pour récupérer seulement les produits qui ont au moins 5 commandes (Order) :
.jpg)
Notez ci-dessus comment nous utilisons à l'aide de la collection « OrderDetails » que LINQ to SQL a créés pour nous sur chaque classe Product (en raison de la relation une-à-plusieurs que nous avons modélisé dans le concepteur LINQ to SQL).
Les outils de mapping objet relationnel (ORM) comme LINQ to SQL, gèrent automatiquement la création et l'exécution du code SQL approprié pour vous lors de l'exécution d’une requête ou de la mise à jour par rapport à leur modèle objet.
L'un des plus grands problèmes/peurs des développeurs sur les nouveaux ORMs est « mais quel code SQL est en réalité exécuté ? ». L'une des possibilités de LINQ to SQL est qu'il rend il très facile de voir exactement quel code SQL sera exécuté lorsque vous lancerez votre application dans le débogueur.
En utilisant la Beta2 de Visual Studio 2008 vous pouvez utiliser un nouveau plugin de visualiseur LINQ to SQL pour facilement voir (et tester) n'importe quel expression de requête LINQ to SQL. Définissez simplement un point d'arrêt puis placez le curseur de la souris sur une requête LINQ to SQL et cliquez sur la loupe pour l’extraire dans le visualiseur avec le débogueur :
.jpg)
[Version RTM] Fonctionnalité également disponible dans la version RTM de Visual Studio 2008.
Cela affiche ensuite une boîte de dialogue qui vous montre le code SQL exacte que LINQ to SQL utilise lors de l'exécution de la requête pour récupérer les objets Product :
.jpg)
Appuyer sur le bouton « Execute » dans cette boîte de dialogue vous permettra d'évaluer l'instruction SQL directement dans le débogueur et d'afficher les résultats de données exacts renvoyés par la base de données :
.jpg)
Il est évidemment facile de voir précisément la logique de requête SQL que LINQ to SQL fait pour vous. Notez que vous pouvez éventuellement substituer l'instruction SQL brute que LINQ to SQL exécute dans le cas où vous souhaitez la modifier - bien que dans 98 % des scénarios je pense que vous vous rendrez compte que le code SQL que LINQ to SQL exécute est vraiment, très bon.
Les requêtes LINQ retournent des résultats qui implémentent l'interface IEnumerable - qui est également une interface que prend en charge l’objet DataBind les contrôles serveur ASP.NET. Cela signifie que vous pouvez lier les données des résultats de n'importe quel requête LINQ, LINQ to SQL ou LINQ to XML pour n'importe quel contrôle ASP.NET.
Par exemple, nous pouvons déclarer un contrôle <asp:gridview> dans une page .aspx comme suit :
.jpg)
J’ai pu ensuite lier les données du résultat de la requête LINQ to SQL que nous avons écrite avant pour le GridView comme suit :
.jpg)
Cela générera ensuite une page qui se présente comme ci-dessous :
.jpg)
En ce moment quand nous évaluons notre requête du produit, nous recherchons par défaut toutes les données de colonne requises pour peupler les entités de classe Product.
Par exemple, cette requête pour rechercher des produits :
.jpg)
Résultats de toutes ces données retournés :
.jpg)
Souvent nous voulons seulement renvoyer un sous-ensemble des données sur chaque produit. Nous pouvons employer les nouvelles data shaping features que LINQ et les nouveaux compilateurs C# et de VB supportent pour indiquer que nous voulons seulement un sous-ensemble des données en modifiant notre requête LINQ to SQL comme ainsi :
.jpg)
Ceci aura seulement pour conséquence que le sous-ensemble de données étant retourné de notre base de données (comme vu par l'intermédiaire du notre visualiseur de débogage) :
.jpg)
Ce qui est bien au sujet de LINQ to SQL est que je peux profiter pleinement de mes associations de classe du modèle de données en mettant en forme mes données. Ceci me permet d’exécuter des requêtes sur des données vraiment utiles (et très efficaces). Par exemple, la requête ci-dessous récupère l'ID et le Name de l'entité Product, le nombre total de commandes qui ont été faites pour le produit concerné, et puis calculer la valeur de revenu de chacun des commandes du produit :
.jpg)
L'expression à droite de la propriété « Revenue » ci-dessus est un exemple d’utilisation de la méthode d’extension « Sum » fournie par LINQ. Il prend en paramètre une expression lambda qui renvoie la valeur de chaque commande d’un article comme argument.
LINQ to SQL est intelligent et peut convertir l'expression LINQ ci-dessus en code SQL ci-dessous quand il est évalué (comme vu par l'intermédiaire du notre visualiseur de débogage) :
.jpg)
Le code SQL ci-dessus entraine des calculs de toutes les valeurs NumOrders et Revenue sur le serveur SQL, et enfin, seules les données ci-dessous sont extraites de la base de données (le rendant vraiment rapide) :
.jpg)
Nous pouvons ensuite lier la séquence de résultat des données à notre contrôle GridView pour générer une belle interface utilisateur :
.jpg)
D'ailleurs - au cas où vous vous le sérié demandé, vous aurez IntelliSense complète dans Visual Studio 2008 lors de l'écriture ces types de requêtes formes LINQ :
.jpg)
Dans l'exemple ci-dessus je suis déclare un type anonyme qui utilise l' initialiseur d’objet afin de mettre en forme et de définir la structure des résultats. Ce qui est réellement utile est que Visual Studio 2008 fournit l’IntelliSense complète, la vérification à la compilation et la refactorisation est prise en charge lorsque vous travaillez avec ces séquences de résultats anonyme ainsi :
.jpg)
L'une des besoins courants dans les scénarios Web consiste à pouvoir générer efficacement la pagination de données sur l’interface utilisateur. LINQ assure la prise en charge intégrée pour les deux méthodes d'extension qui rendent cela à la fois simple et efficace - les méthodes Skip() et Take().
Nous pouvons utiliser les méthodes Skip() et Take() ci-dessous pour indiquer que nous souhaitons uniquement retourner 10 objets Product - en commençant à un certain enregistrement de produit que nous spécifions en tant qu'argument :
.jpg)
Noter ci-dessus que je n'ai pas ajouté l'opérateur Skip() et Take() sur la déclaration de requête initiale products - mais au lieu de cela je l’ai ajouté ultérieurement à la requête (lors de la liaison avec la source de données du GridView). Des personnes me demandent souvent « mais cela ne signifie t-il pas que la requête sélectionne d'abord toutes les données de la base de données et puis effectue la pagination dans le niveau intermédiaire (ce qui est très mauvais) ? » Non. La raison est que LINQ utilise un modèle d’exécution différée- ce qui signifie que la requête n'est réellement exécutée lorsque vous essayez d'itérer sur les résultats.
L'un des avantages de ce modèle d’exécution différée est qu'il vous permet de façon à ce qu'elles soient joliment composées de requêtes sur plusieurs instructions de code (ce qui améliore la lisibilité du code). Il vous permet également de composer des requêtes en dehors d'autres requêtes - ce qui permet certains scénarios de composition de requête très flexible et leur réutilisation.
Une fois que j’ai défini la méthode BindProduct() ci-dessus, je peux écrire le code ci-dessous dans ma page pour récupérer l'index de départ de la QueryString et paginer la liste des produits et des afficher dans le Gridview :
.jpg)
Ceci vous donnera ensuite une page avec des produits, filtrés uniquement pour la liste avec plus de 5 commandes, qui montre de manière dynamique des données calculées d’un produit et qui est paginable via l’argument QueryString :
.jpg)
Remarque : Lorsque vous travaillez avec SQL 2005, LINQ to SQL va utiliser la fonction SQL ROW_NUMBER() pour exécuter la totalité de la logique de pagination de données dans la base de données. Cela garantit que seuls les 10 enregistrements qui nous intéressent dans l'affichage de la page en cours sont retournés à partir de la base de données lorsque vous exécutez le code ci-dessus :
.jpg)
Cela le rend efficace et facile à paginer pour des séquences avec de grande quantité de données.
Normalement la procédure pas à pas ci-dessus fournit une bonne vue d'ensemble de certaines opportunités de requête de données pratiques et amusantes que fournit LINQ to SQL. Pour plus d'informations sur les expressions LINQ et la nouvelle syntaxe du langage pris en charge par les compilateurs C# et VB avec Visual Studio 2008, veuillez consulter ces publications antérieures aux miennes (en anglais) :
Dans mon prochain article de cette série LINQ to SQL je traiterais comment nous pourrons proprement ajouter une logique de validation à nos classes de modélisation de données, puis je démontrerais comment nous pouvons l’utiliser pour encapsuler la logique métier qui s'exécute chaque fois que nous mettons à jour, insérerons ou supprimons nos données. Je vais ensuite couvrir les scénarios de requêtes lazy loading et eager loading, comment utiliser le nouveau control <asp :LINGDataSource> pour prendre en charge le databiding déclaratif des contrôles ASP.NET, la résolution d'erreur d'accès concurrentiel optimiste et plus encore.
J’espère que ceci vous aura aidé,
Scott
Traduction autorisée par
Scott Guthrie.
Merci à
Thomas Lebrun pour la relecture et à
Mitsu Furuta pour ses conseils.