Exporter (0) Imprimer
Développer tout

Nouvelles fonctionnalités de DataSet dans Visual Studio 2005

Visual Studio 2005
Paru le Febrary 1, 2005 | Dernière mise à jour le 23 août 2005
Par Jackie Goldstein

S'applique à :
Microsoft ADO.NET 2.0
Microsoft Visual Studio 2005 (version bêta)

Résumé : Découvrez les nouvelles fonctionnalités de la classe typée DataSet et de la nouvelle classe TableAdapter générées par Visual Studio 2005, ainsi que les outils permettant de concevoir ces classes. Découvrez également les nouveaux composants BindingSource et BindingNavigator, ainsi que comment les utiliser pour créer rapidement des applications WinForms flexibles et liées aux données. (20 pages imprimées)

Télécharger l’exemple de code associé VSDatasetSamples.exe.

Sur cette page

Introduction Introduction
Sources de données Sources de données
Création de formulaires orientés données Création de formulaires orientés données
Personnalisation du code généré Personnalisation du code généré
Conclusion Conclusion

Introduction

Dans un précédent article, New DataSet Features in ADO.NET 2.0, j’ai abordé certaines des modifications et améliorations de la classe ADO.NET DataSet et des classes associées, telles que DataSet, DataTable et DataView. Toutes ces classes font partie de la bibliothèque de classes de base du Microsoft .NET Framework.

Dans cet article, j’aborderai le développement avec ces classes (et les classes dérivées) dans l’environnement de développement Microsoft Visual Studio 2005. En particulier, cet article traite des modifications de la classe typée DataSet et de la nouvelle classe typée TableAdapter, générées par Visual Studio 2005. Cet article examine également les concepteurs et outils qui offrent une flexibilité et une productivité importantes pour le développement des aspects orientés données de votre application. Pour expliquer les différents concepts et fonctionnalités, je vais détailler la procédure typique pour un développeur qui implémente la partie données d’une application. Ces exemples de code utilisent la base de données Northwind fournie à titre d’exemple avec Microsoft SQL Server (et MSDE) 7.0 et 2000.

Sources de données

Visual Studio 2005 introduit le concept de source de données pour un projet. Une source de données représente les données disponibles pour une application. Ces données ne proviennent pas nécessairement d’une base de données : l’Assistant Configuration de source de données utilisé pour définir une source de données vous permet d’obtenir les données à partir de trois sources différentes :

  1. Base de données : Il peut s’agir soit d’une base de données basée sur un serveur tel que SQL Server ou Oracle, soit d’une base de données basée sur des fichiers, tels que Access ou SQL Server Express. Visual Studio génère automatiquement des DataSets typés et d’autres classes et les ajoute à votre projet.

  2. Objet : n'importe quel objet avec des propriétés publiques peut être la source des données. Il n’est pas nécessaire d’implémenter des interfaces spéciales.

  3. Service Web : la création d’une source de données à partir d’un service Web crée des objets qui correspondent au type de données renvoyé par le service Web.

Le rôle de la source de données est double. Tout d’abord, il s’agit d’un moyen de faciliter la spécification, la conception et la génération de classes fortement typées qui représentent les données de l’application. Ensuite, elle offre un mécanisme flexible mais uniforme pour créer très rapidement des interfaces utilisateur WinForm et WebForms riches et fonctionnelles. Dans cet article, nous allons voir à quel point ce processus est rapide, facile et flexible.

Dans cet article, nous allons nous concentrer sur la création de sources de données de base de données (DataSet) et sur leur utilisation dans les applications WinForms. Il est toutefois important de se rappeler des deux points suivants :

  • Une fois qu’une source de données a été créée, vous pouvez l’utiliser de la même façon, peu importe d’où proviennent les données. Cela signifie que, tout comme vous pouvez facilement (et graphiquement) lier une source de données basée sur une base de données à une grille ou à un ensemble de contrôles, il en va de même des données qui proviennent en fait d’un service Web ou de vos objets métier personnalisés.

  • Les sources de données sont définies de la même façon, qu’elles soient destinées à une utilisation dans une application WinForms ou WebForms. Les différents fournisseurs de données font également l’objet d’une abstraction, de sorte que si votre accès aux données est exposé uniquement avec DataSets et TableAdapters, il vous suffit pour changer la base de données de changer la chaîne de connexion et de régénérer les classes.

Classes DataSet et TableAdapter typées

La source de données d’une base de données est la combinaison d’un DataSet fortement typé et d’une ou plusieurs paires de classes DataTables et TableAdapters fortement typées. L’idée d’un DataSet typé n’est pas nouvelle : elle existait dans Visual Studio 2002/2003. Un DataSet typé est une classe générée, dérivée de la classe DataSet générique du .NET Framework, mais elle présente un schéma défini, avec les propriétés et méthodes propres à ce schéma. Dans le même temps, pour chaque table de DataSet, trois autres classes dérivées sont générées : les classes DataTable, DataRow et DataRowChangeEvent propres à ce DataSet. Chacune de ces classes présente un schéma, des propriétés et des méthodes spécifiques pour la table associée. Par exemple, si je définis une source de données basée sur la table Employees de Northwind, les classes suivantes sont générées :

  • NorthwindDataSet

  • EmployeesDataTable

  • EmployeesDataRow

  • EmployeesRowChangeEvent

Ces quatre classes constituent le DataSet typé. Dans Visual Studio 2005, une cinquième classe est également générée, à savoir la classe typée TableAdapter nommée EmployeesTableAdapter, que nous allons voir par la suite. Bien entendu, si vous définissez les requêtes de manière dynamique, vous ne pouvez pas gérer les DataSets typés et vous devez utiliser le DataSet standard.

Pourquoi utiliser un DataSet typé ? Outre le fait de vous forcer à concevoir le schéma des données à l’avance, un DataSet typé offre plusieurs avantages concrets :

  1. Les classes DataSets, DataTables, DataRows et RowChangeEvent sont propres au schéma traité.

  2. Les tables, colonnes et relations sont exposées comme des propriétés nommées, plutôt que comme des éléments de collection générique.

  3. En raison de (2), IntelliSense et la saisie semi-automatique des instructions sont totalement pris en charge dans l’éditeur de code Visual Studio.

  4. Également en raison de (2), la vérification de type lors de la compilation est possible (par exemple, une orthographe incorrecte pour un nom de champ est détectée lors la compilation et non lors de l’exécution).

  5. Le code est ainsi plus concis et lisible : Au lieu de :

    country = dsNorthwind.Tables ("Employees").Rows (row) ("Country")

    vous avez

    country = dsNorthwind.Employees (row).Country

Au final, l’assistance à la conception et à la compilation offerte par les DataSets typés réduit de manière significative non seulement le temps de développement initial, mais également le temps nécessaire au débogage et à la stabilisation de l’application.

Le concept de TableAdapter, à l’inverse, est nouveau dans Visual Studio 2005. L’idée est qu’une classe TableAdapter fortement typée est l’équivalent fortement typé de la classe DataAdapter standard. Utilisez TableAdapter pour vous connecter à une base de données et exécuter les requêtes (ou les procédures stockées) sur cette base de données, ainsi que pour remplir une classe DataTable associée avec des données. Chaque paire DataTable-TableAdapter est simplement appelée classe TableAdapter.

La classe TableAdapter est essentiellement un wrapper autour d’une classe DataAdapter standard, ce qui offre plusieurs avantages :

  • La même classe TableAdapter peut être utilisée sur plusieurs formulaires ou composants, de sorte que les modifications des requêtes/commandes sont automatiquement répercutées dans toutes les instances. Il existe une différence avec la situation existante, dans laquelle chaque composant qui accède à la base de données doit comporter sa propre classe DataAdapter configurée individuellement. Il est ainsi beaucoup plus facile de garantir la synchronisation de DataTables et DataAdapters.

  • Plutôt que d’utiliser plusieurs DataAdapters (ou du code de basculement écrit à la main) pour avoir plusieurs requêtes/commandes pour une même classe DataTable, une classe TableAdapter vous permet de définir facilement plusieurs commandes pour une classe DataTable donnée.

  • Les commandes de remplissage présentent des noms lisibles (conviviaux), et la classe TableAdapter inclut le code permettant de remplir automatiquement les informations de type et de valeur pour tous les paramètres de ces méthodes de commande. Vous n’avez plus à vous soucier du passage de types de données propres au fournisseur, tels que SqlInt.

Un extrait de code simple permet d’illustrer ces fonctionnalités. Dans Visual Studio 2002/2003, même en utilisant un DataSet typé, le code permettant d’exécuter une requête simple avec deux paramètres n’est pas évident : pour la requête

SELECT FirstName, LastName from Employees WHERE Country = @country AND City = @city



nous devrions écrire un code semblable au suivant :

Me.SqlAdapter1.SelectCommand.Parameters ("@country").value =     
Me.CountryListbox.SelectedValue.Trim()   
Me.SqlAdapter1.SelectCommand.Parameters ("@city").value =     
Me.CityTextbox.Text.Trim()   
Me.SqlAdapter1.Fill (Me.NorthwindDataSet.Employees)


Bien sûr, à mesure que le nombre de paramètres augmente, le nombre de lignes de code augmente également. Plus important, la difficulté de mémoriser et de saisir correctement le nom de chaque paramètre augmente également. Même si je saisis correctement le nom du paramètre, je dois me rappeler le type de données du paramètre. Le plus ennuyeux est que si je saisis un nom de champ incorrect ou que je tente d’affecter une valeur d’un type incorrect, je ne m’en rendrai pas compte avant l’exécution !

Avec la classe TableAdapter de Visual Studio 2005, une fois que j’ai défini la commande FillByCountryAndCity, il me suffit pour l’utiliser d’écrire une seule ligne de code, en passant les valeurs des paramètres :

Me.EmployeesTableAdapter.FillByCountryAndCity ( _
   Me.NorthwindDataSet.Employees, Me.CountryListbox.SelectedValue.Trim(), 
      _    Me.CityTextbox.Text.Trim() )



Il est important de noter que non seulement nous obtenons plusieurs commandes nommées à partir d’une même classe TableAdapter, mais que ces commandes sont fortement typées. Cela signifie que lorsque nous écrivons du code dans Visual Studio, IntelliSense nous permet de voir ces commandes comme des méthodes de TableAdapter. En outre, les paramètres de ces commandes sont vérifiés lors de la compilation, et une info-bulle s’affiche avec la définition des types de méthode et de paramètre. La classe TableAdapter peut présenter plusieurs méthodes qui exécutent différentes commandes et acceptent différents paramètres. Nous allons par la suite examiner de plus près la classe TableAdapter, lors de la génération de notre exemple de formulaire.

Démarrage : création d’une source de données

Dans cet article, nous allons créer un formulaire afin d’afficher les informations concernant chacune des commandes de la base de données Northwind. La première chose à faire après l’ouverture d’un nouveau projet Visual Basic WinForms consiste à ajouter une nouvelle source de données à notre projet (nous allons faire cela dans Visual Basic, mais la procédure est la même dans C#).

Pour ajouter une source de données :

  1. Affichez la fenêtre Sources de données (si elle n’est pas déjà affichée) en sélectionnant Afficher les sources de données dans l’élément de menu Données du menu principal de Visual Studio.

  2. Dans la fenêtre Sources de données, cliquez sur le bouton Ajouter une nouvelle source de données de la barre d'outils. Cela permet de démarrer l’Assistant Configuration de source de données, qui combine une grande partie des fonctionnalités de l’Assistant Configuration de DataAdapter et les outils de génération de DataSet dans Visual Studio 2002/2003.

  3. Si votre version de Visual Studio inclut toujours une page de bienvenue pour les assistants, sélectionnez Suivant. La page Choisir un type de source de données s’affiche.

  4. Sélectionnez Base de données.

  5. Sélectionnez Suivant. La page Choisir votre connexion de données s’affiche.

  6. Sélectionnez Nouvelle connexion. La boîte de dialogue Ajouter une connexion s’affiche.

  7. Entrez les informations permettant de vous connecter à votre instance de SQL Server ou MSDE et à la base de données Northwind.

  8. Sélectionnez OK afin de faire disparaître la boîte de dialogue.

  9. Notez que la chaîne de connexion est désormais enregistrée en tant que propriété de paramètre et est accessible par

    My.Settings.NorthwindConnectionString
    



    En C#, nous aurions

    VSDataSets.Properties.Settings.Default.NorthwindConnectionString;
    

  10. Sélectionnez Suivant. La page Choisir vos objets de base de données s’affiche.

  11. Notez que vous pouvez choisir parmi Tables, Vues, Procédures stockées et Fonctions.

    Développez le nœud Tables et sélectionnez les tables Orders et Order Details. Nous allons utiliser toutes les colonnes des tables, mais vous pouvez sélectionner uniquement les colonnes dont vous avez besoin pour votre application.

  12. Sélectionnez Terminer afin de quitter l’assistant.

La figure 1 illustre la fenêtre Sources de données résultante avec la table Order Details développée pour afficher toutes ses colonnes.

newdtastvs05_fig1.gif

Figure 1. Table Order Details dans la fenêtre Sources de données

Si vous souhaitez entrer de nouveau dans l’Assistant Configuration de source de données afin d’apporter des modifications, vous pouvez sélectionner Configurer le DataSet à l'aide de l'Assistant dans la barre d'outils de la fenêtre Sources de données ou dans le menu contextuel qui s’affiche lorsque vous cliquez avec le bouton droit de la souris sur un élément de cette fenêtre. En revanche, le Concepteur de DataSet est un outil plus puissant pour modifier le DataSet et le(s) TableAdapter(s) générés.

Le concepteur de DataSet

Visual Studio 2005 inclut le Concepteur de DataSet : il s’agit d’un outil réellement conçu pour spécifier et modifier les DataSets et leurs TableAdapters associés. La situation de Visual Studio 2002/2003 a été nettement améliorée, car nous étions alors contraints d’utiliser un éditeur de schéma XML pour définir des DataSets fortement typés. Les définitions DataSet et TableAdapter sont toujours enregistrées dans un fichier .XSD et il existe toujours un éditeur XML pour les cas où vous souhaitez réellement modifier des schémas XML. Mais les ressemblances s’arrêtent là. Le but n’est pas que le Concepteur de DataSet prenne en charge des fichiers XSD arbitraires, mais il constitue simplement un format de fichier commode.

Pour accéder au Concepteur de DataSet, sélectionnez Modifier le DataSet à l'aide du Concepteur dans la barre d'outils de la fenêtre Sources de données ou dans le menu contextuel qui s’affiche lorsque vous cliquez avec le bouton droit de la souris sur un élément quelconque de cette fenêtre. Lors de la conception des DataSets et de leurs DataTables, le concepteur est probablement très similaire aux autres outils que vous avez eu l’occasion d’utiliser pour concevoir des bases de données. Vous pouvez ajouter une table à partir de la base de données à laquelle vous êtes connecté en faisant glisser un objet de base de données (par exemple une table, une vue ou une procédure stockée) à partir de l’Explorateur de serveurs sur la surface de conception, ou en démarrant l’Assistant Configuration de TableAdapter en sélectionnant Ajouter un TableAdapter dans l’élément de menu Données du menu contextuel du concepteur. Dans la mesure où un DataSet peut également comporter des tables qui sont chargées directement et qui ne sont pas connectées à une base de données, vous pouvez ajouter une table indépendante en sélectionnant Ajouter un DataTable dans les menus. Bien sûr, vous pouvez également ajouter et/ou renommer des colonnes dans l’éditeur. Une autre fonctionnalité intéressante est que l’éditeur reconnaît automatiquement les relations entre les tables de la base de données et définit les relations correspondantes entre les tables du DataSet.

La figure 2 illustre notre source de données, constituée des tables Orders et Order Details, dans le Concepteur de DataSet. Notez qu’à chaque DataTable est étroitement associé le TableAdapter correspondant, utilisé pour alimenter la table avec des données et (éventuellement) mettre à jour la base de données avec les modifications apportées à ces données.

newdtastvs05_fig2.gif

Figure 2. Tables Orders et Order Details dans la source de données

L’Assistant Configuration de TableAdapter

Vous démarrez l’Assistant Configuration de TableAdapter dans le Concepteur de DataSet en sélectionnant Ajouter une requête ou Configurer (une requête existante) dans le menu Données principal ou dans le menu contextuel qui s’affiche lorsque vous cliquez avec le bouton droit de la souris sur un TableAdapter dans le concepteur. Cet assistant est identique à l’Assistant Configuration de DataAdapter de Visual Studio 2002/2003 : à l’exception des deux pages complémentaires offertes. La première est la page Choisir un type de requête, illustrée dans la figure 3. Dans la mesure où le TableAdapter est le point central pour toutes les commandes exécutées sur une table donnée, il vous permet non seulement de définir plusieurs commandes Sélection/Remplissage, mais également plusieurs requêtes de type quelconque : Mettre à jour, Insérer, Supprimer, ou une requête qui renvoie une valeur unique. Notez que ces requêtes de mise à jour sont des méthodes nommées du TableAdapter et doivent être appelées directement. Elles complètent les requêtes de mise à jour qui sont appelées automatiquement lorsque vous exécutez la méthode Update du TableAdapter : comme avec la méthode DataAdapter.Update.

La deuxième page supplémentaire de l’assistant est la page Choisir les méthodes à générer. Vous devez choisir les noms de chacune des méthodes de requête/commande que vous définissez. L’assistant offre une méthode Fill et une méthode Get pour chaque commande, comme illustré figure 3. La méthode Fill nécessite que vous fournissiez le DataTable à remplir, tandis que la version Get renvoie un DataTable nouvellement créé et rempli.

newdtastvs05_fig3.gif

Figure 3. Méthodes Fill et Get dans la page Choisir les méthodes à générer

Pour une utilisation typique, vous allez définir plusieurs commandes Fill pour un TableAdapter, qui renvoient les mêmes colonnes de schéma, mais avec différentes clauses WHERE. C’est la raison pour laquelle, par défaut, l’assistant offre le préfixe FillBy et GetDataBy pour les noms des méthodes. Bien sûr, vous pouvez attribuer aux méthodes n'importe quel nom souhaité.

Bien qu’un TableAdapter puisse comporter plusieurs commandes Fill, un seul jeu de commandes de mise à jour est exécuté lorsque la méthode Update du TableAdapter est appelée. Elles sont générées automatiquement, sur la base de la requête principale du TableAdapter. La requête définie lors de la création initiale du TableAdapter est considérée comme la requête principale pour le TableAdapter. Si des requêtes définies par la suite renvoient un schéma différent du schéma de la requête principale, le concepteur vous en informe avec un message. De la même façon, si vous modifiez le schéma de la requête principale, Visual Studio modifie vos autres requêtes afin qu’elles correspondent à ce schéma.

Ajout d’une nouvelle commande avec l’Assistant Configuration de TableAdapter

Ajoutons à présent une autre commande au TableAdapter de la table Orders.

  1. Ouvrez le Concepteur de DataSet en sélectionnant Modifier le DataSet à l'aide du Concepteur dans la barre d'outils de la fenêtre Sources de données.

  2. Sélectionnez le TableAdapter de Orders, puis sélectionnez Ajouter une requête dans le menu contextuel.

  3. Sélectionnez Suivant dans la page Bienvenue si elle existe toujours dans votre version de Visual Studio. La page Choisir un type de commande s’affiche.

  4. Sélectionnez Suivant afin d’accepter la valeur par défaut pour Instructions SQL. La page Choisir un type de requête s’affiche.

  5. Sélectionnez Suivant afin d’accepter l’instruction SELECT par défaut. La page Spécifier une instruction SQL SELECT s’affiche.

  6. Entrez l’instruction SQL suivante :

    SELECT OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, 
    ShippedDate, ShipVia, Freight, ShipName, ShipAddress, ShipCity, 
    ShipRegion, ShipPostalCode, ShipCountry 
    FROM Orders
    WHERE CustomerID = @CustID
    

    Toutes les commandes (Orders) du client spécifié par le paramètre @CustID sont renvoyées à la requête.

  7. Sélectionnez Suivant. La page Choisir les méthodes à générer s’affiche

  8. Laissez les cases cochées. Remplacez les noms des méthodes respectivement par FillByCustomer et GetDataByCustomer.

  9. Cliquez sur Suivant, puis sur Terminer afin de compléter le processus.

Si vous examinez OrdersTableAdapter dans le Concepteur de DataSet, vous constaterez qu’il affiche à présent une deuxième paire de commandes, à savoir FillByCustomer et GetDataByCustomer, qui accepte une valeur CustomerID comme paramètre. Quel est le type (.NET) de ce paramètre de méthode ? Examinons cela.

Un œil en coulisses

Lorsque vous apportez des modifications dans le Concepteur de DataSet ou dans les assistants associés, Visual Studio génère le code pour un ensemble de classes typées. En particulier, il génère les classes suivantes :

  1. Une classe DataSet

  2. Une classe DataTable

  3. Une classe TableAdapter

  4. Une classe DataRow

  5. Une classe DataRowChangeEvent

Excepté pour la classe DataSet, qui est unique pour chaque source de données, chacune des quatre autres classes se répète pour chaque table définie dans le DataSet. Vous pouvez voir le code de ces classes en procédant de la façon suivante :

  1. Dans la fenêtre Explorateur de solutions, cliquez sur le bouton Afficher tous les fichiers dans la barre d'outils afin d’afficher tous les fichiers associés au projet.

  2. Développez le nœud pour le fichier NorthwindDataSet.xsd.

  3. Double-cliquez sur le nœud de fichier pour NorthwindDataSet.Designer.vb. Il s’agit du code généré pour implémenter les classes qui constituent notre DataSet.

  4. Ouvrez la zone de liste à gauche de la fenêtre de code. Vous pouvez voir la liste des classes dans ce fichier :
    - NorthwindDataSet
    - Order_DetailsDataTable
    - OrdersDataTable
    - Order_DetailsRow
    - OrdersRow
    - Order_DetailsRowChangeEvent
    - OrdersRowChangeEvent
    - Order_DetailsTableAdapter
    - OrdersTableAdapter

  5. Sélectionnez la classe OrdersTableAdapter dans la zone de liste à gauche.

  6. Sélectionnez la méthode FillByCustomer dans la zone de liste à droite. Le code de cette méthode s’affiche, comme illustré ci-dessous :

     
          Public Overloads Overridable Function FillByCustomer(ByVal dataTable 
             As NorthwindDataSet.OrdersDataTable, ByVal CustID As String) As Integer
                Me.Adapter.SelectCommand = Me.CommandCollection(1)
                If (CustID Is Nothing) Then
                    Throw New System.ArgumentNullException("CustID")
                Else
                    Me.Adapter.SelectCommand.Parameters(0).Value = CType(CustID,String)
                End If
                If (Me.m_clearBeforeFill = true) Then
                    dataTable.Clear
                End If
                Dim returnValue As Integer = Me.Adapter.Fill(dataTable)
                Return returnValue
            End Function
    

Cet extrait de code nous permet d’apprendre plusieurs choses.

  • Les méthodes FillByCustomer acceptent en fait deux paramètres : un OrdersDataTable à remplir et un paramètre CustID, qui est une chaîne.

  • Sans parcourir tout le code du fichier, nous pouvons voir que la classe TableAdapter gère une collection de commandes, à partir de laquelle elle affecte automatiquement la commande correcte au DataAdapter .NET qu’elle utilise pour communiquer avec la base de données.

  • La méthode vérifie qu’une instance d’un paramètre d’état a été passée à la méthode (si la propriété AllowDBNull du paramètre est définie sur False).

  • La valeur du paramètre CustID est affectée au paramètre (déjà configuré) de la propriété SelectCommand du DataAdapter.

  • Une fois que tout est configuré, la méthode DataAdapter.Fill () standard est appelée afin de remplir OrdersDataTable.

Rappelez-vous qu’il ne s’agit pas de code devant être écrit par vous. Tout a déjà été généré et configuré. Prenez le temps d’examiner le code des autres classes générées. Vous comprendrez mieux la façon dont ces classes sont implémentées, et vous y trouverez probablement quelques bonnes idées de codage.

Remarque : Bien que le DataSet typé et ses classes associées, notamment TableAdapters, soient tous générés dans un fichier source unique, les TableAdapters sont générés dans un espace de noms séparé. Cela reflète le fait qu’il doit exister une séparation entre les objets d’entité (DataSets) et les objets réels d’accès aux données (TableAdapters).

Création de formulaires orientés données

Maintenant que nous avons généré un DataSet typé, il est temps de générer un formulaire qui affiche ces données. Je ne vais pas entrer dans tous les détails et aborder toutes les nouvelles fonctionnalités de WinForms et de la liaison de données dans le .NET Framework 2.0 et Visual Studio 2005 (bien qu’il y aurait matière à approfondir), mais c’est l’occasion de voir ce qui a été fait pour rendre plus simple et plus flexible la création de formulaires orientés données.

Composants de données dans la boîte à outils

Si vous avez l’habitude de créer votre code orienté données en commençant avec les composants de données standard sous l’onglet Données de la boîte à outils, vous risquez d’être un peu perdu en ouvrant Visual Studio 2005, car vous ne les trouverez peut-être pas. Cela est bien sûr voulu : Microsoft souhaite nous inciter à tirer parti des nouvelles classes typées DataSets et TableAdapters. Si vous souhaitez absolument utiliser les anciens composants non typés, vous pouvez les ajouter manuellement à la boîte à outils. Je déconseille vivement de faire cela ; en exploitant les nouveaux TableAdapters avec la technologie de classe partielle, les nouvelles classes typées DataSets et TableAdapters sont beaucoup plus faciles à utiliser et à étendre.

Vous en saurez plus sur ces décisions de conception en consultant le blog de l'équipe Visual Basic.

En particulier, examinez deux des contributions de Steve Lasker : Why are the Data Components no longer on the Toolbox? (Pourquoi les composants de données ne sont-ils plus dans la boîte à outils ?),et Why can't I drag from Server Explorer to my form? (Pourquoi ne puis-je plus faire glisser de l’Explorateur de serveur vers mon formulaire ?)

Lorsque vous ouvrez un formulaire dans le concepteur de Visual Studio, la boîte à outils présente un onglet portant le nom de votre projet. Une fois que vous avez ajouté une source de données dans le projet et généré au moins un objet, l'onglet inclut les objets DataSet et TableAdapter que vous avez créés. Bien qu'il soit possible de faire glisser les composants vers le concepteur de formulaire, il est probable que nous ne procédiez pas de la sorte (si, toutefois, vous implémentez un composant d'accès aux données à l'aide du concepteur, la procédure est pratique). Normalement, pour créer un formulaire centré sur les données, vous allez utiliser une des trois approches disponibles. Examinons la première méthode, qui est la plus simple et sans doute la plus courante. On parle à son sujet de liaison de données par glissement « Drag Once ».

  1. Double-cliquez sur Form1.vb dans l’Explorateur de solutions afin d’ouvrir Form1 dans le Concepteur de formulaires de Visual Studio.

  2. Dans la fenêtre Sources de données, développez le nœud de la table Orders.
    Notez qu’une icône est associée à chaque table et chaque colonne du DataSet. Ces icônes représentent le type de contrôle WinForm (ou « drop type ») qui sera utilisé pour lier les données si vous faites glisser la table ou la colonne sur un formulaire. Vous pouvez changer le type de contrôle en sélectionnant un élément et en choisissant un contrôle dans la liste déroulante associée. Notez que la liste inclut des options pour Aucun (rien ne s’affiche), ainsi que pour Personnaliser (vous spécifiez le contrôle souhaité).

    Ces icônes et la liste « drop type » sont visibles uniquement si la fenêtre actuellement active est un concepteur de formulaires (ou de composants). Dans le cas contraire, vous ne pouvez pas faire glisser des contrôles à partir de la fenêtre Sources de données, et les icônes changent afin d’indiquer cela.

  3. Remplacez le type de contrôle DataGridView de la table Orders par Details. Cela signifie que lorsque vous faites glisser l’ensemble de la table Orders sur un formulaire, plutôt que de créer un formulaire qui affiche toutes les données dans une grille (toutes les lignes à la fois), un formulaire affichant les détails des lignes une par une est créé. Pour une vue Détails, un libellé et un contrôle sont ajoutés pour chaque colonne, le type de contrôle étant celui spécifié dans la fenêtre Sources de données.

  4. Faites glisser la table Orders de la fenêtre Sources de données sur Form1 dans le concepteur.

  5. Sélectionnez les sept (7) derniers champs (avec leurs libellés) et faites-les glisser le long des sept premiers champs, de sorte que le formulaire ressemble à celui de la figure 4.
    newdtastvs05_fig4.gif
    Figure 4. Form1 dans le concepteur

  6. Démarrez l’application et vérifiez qu’elle fonctionne, en parcourant les enregistrements avec les boutons de navigation de la barre d'outils en haut du formulaire.
    Examinons à présent ce que Visual Studio a fait lorsque nous avons fait glisser une table de source de données sur un formulaire. En examinant la barre des composants sous le formulaire, nous voyons qu’il a ajouté quatre composants au formulaire. Nous connaissons (et apprécions ?) déjà deux de ces composants : NorthwindDataSet et OrdersTableAdapter. Le composant OrdersTableAdapter est utilisé pour remplir le composant OrdersDataTable de NorthwindDataSet avec les données de la base. Même la ligne de code permettant cette opération Fill est déjà écrite et ajoutée automatiquement au gestionnaire d’événements Load de Form1.

    Me.OrdersTableAdapter.Fill(Me.NorthwindDataSet.Orders)
    

La classe pivotale pour la liaison de données est la classe BindingSource, à savoir OrdersBindingSource dans le cas présent. La classe BindingSource (appelée DataConnector dans la version bêta 1) fournit les services requis pour la liaison des contrôles sur un formulaire. Elle fournit une couche d’indirection entre une source de données et les contrôles qui y sont liés. Vous associez BindingSource à une source de données en définissant les propriétés DataSource et DataMember de BindingSource, puis vous liez les contrôles à BindingSource par l’ajout à la collection DataBindings des contrôles. Toute l’interaction avec les données, telle que la navigation dans les enregistrements, le tri, le filtrage et la modification, est effectuée via BindingSource. BindingSource permet également l’accès aux données sous-jacentes via les propriétés List, Item et Current.

L’autre composant ajouté est OrdersBindingNavigator. Une classe BindingNavigator est une barre d'outils qui fournit une interface utilisateur standard pour la navigation et la manipulation de données sur un formulaire. BindingNavigator (également appelé DataNavigator dans la version bêta 1) est un contrôle ToolStrip, avec un ensemble de boutons préconfigurés. Il est associé à un BindingSource comme source de données et fournit des boutons de barre d'outils pour contrôler la navigation via les données disponibles. En revanche, si au lieu de contrôler la navigation vous souhaitez répondre à certains événements de navigation, vous devez récupérer les événements de l’objet BindingSource.

Génération d’un formulaire maître-détails

Maintenant que nous avons un formulaire qui affiche les données d’une table unique, est-il facile (ou difficile) d’afficher les données d’une deuxième table liée, dans un format Maître-Détails ? Poursuivons la procédure sur Form1 :

  1. Nous allons à présent utiliser la liaison de données de type « Relier les points » pour créer le formulaire : nous allons faire glisser un contrôle de la boîte à outils et le positionner sur le formulaire, puis faire glisser un élément de la fenêtre Source de données et le déposer sur ce contrôle afin de les associer.

  2. Sélectionnez le contrôle DataGridView sous l’onglet Tous les Windows Forms dans la boîte à outils. Faites-le glisser sur Form1 et positionnez-le de sorte qu’il occupe l’essentiel de la moitié supérieure du formulaire.

  3. Revenez à la fenêtre Source de données, comme illustré figure 5. Notez que la table Order Details apparaît deux fois dans cette fenêtre. La première fois, il s’agit d’un enfant direct de NorthwindDataSet et d’un frère de la table Orders. La deuxième fois, elle apparaît en tant qu’enfant de la table Orders, ce qui indique qu’il s’agit d’une table liée. Si nous souhaitions afficher indépendamment la table Order Details sur le formulaire, nous choisirions l’occurrence de la table Order Details située directement sous NorthwindDataSet. En revanche, lorsque (comme c’est notre cas) nous souhaitons afficher la table Order Details avec sa relation avec la table Orders (maître), nous choisissons l’occurrence de la table Order Details située directement sous la table Orders.
    newdtastvs05_fig5.gif
    Figure 5. Table Order Details dans la fenêtre Source de données

  4. Sélectionnez la table Order Details qui apparaît sous la table Orders et faites-la glisser sur le DataGridView sur Form1.

  5. Notez les composants Order_DetailsBindingSource et Order_detailsTableAdapter ajoutés à la barre des composants de Form1.

  6. Exécutez l’application et utilisez BindingNavigator pour naviguer dans les enregistrements de la table Orders, comme illustré dans la figure 6. Notez la façon dont les enregistrements Order Details affichés dans DataViewGrid changent automatiquement afin d’afficher uniquement ceux liés à l’enregistrement Orders actuel.
    newdtastvs05_fig6.gif
    Figure 6. BindingNavigator dans la table Orders

Personnalisation du code généré

Précédemment, lorsque nous avons examiné le code des classes de notre DataSet, vous avez peut-être remarqué qu’il y a en fait deux fichiers de code Visual Basic, à savoir NorthwindDataSet.Designer.vb et NorthwindDataSet.vb. S’il n’y a pas de fichier NorthwindDataSet.vb, revenez au Concepteur de DataSet et double-cliquez sur l’arrière-plan du concepteur afin de provoquer la création du fichier.

Ces deux fichiers sont utilisés pour implémenter les classes qui constituent notre DataSet. La raison de la présence de deux fichiers est de pouvoir tirer parti d’une nouvelle fonctionnalité très simple mais très puissante, appelée classes partielles. Les classes partielles sont une fonctionnalité du compilateur qui permet de répartir sur plusieurs déclarations la définition d’une classe (ou d’une structure). Les différentes déclarations peuvent se trouver dans différents fichiers de code source, dès lors que les déclarations se trouvent toutes dans le même assembly et le même espace de noms. Visual Studio utilise de manière intensive cette fonctionnalité pour séparer le code généré par le concepteur du code écrit par le développeur pour la même classe. Par exemple, dans Visual Studio 2002/2003, le code d’un formulaire fait partie d’une déclaration de classe pour ce formulaire, par exemple

Public Class Form1
    Inherits System.Windows.Forms.Form



Le code d’initialisation de ce formulaire, notamment les contrôles positionnés sur le formulaire, est généré par Visual Studio. Ce code se trouve dans la méthode InitComponent (), qui apparaît par défaut avant le code écrit par l’utilisateur, dans une région de code nommée « Code généré par le Concepteur Windows Form ». Cette région est normalement laissée fermée afin de limiter l’encombrement et la confusion avec le code que vous écrivez. Dans Visual Studio 2005, ce code est encore moins perturbant, puisqu’il se trouve dans un fichier totalement distinct, nommé Form1.Designer.vb. Là encore, vous pouvez voir le contenu de ce fichier si vous le souhaitez : cliquez sur Afficher tous les fichiers dans la barre d'outils de l’Explorateur de solutions, développez le nœud Form1.vb, puis double-cliquez sur Form1.Designer.vb afin de l’afficher dans l’éditeur de code. Le fichier Form1.vb contient uniquement le code que vous, en tant que développeur, avez écrit pour la classe Form1.

S’agissant du code du DataSet et des classes associées, cette utilisation de classes partielles et de fichiers différents pour séparer le code du concepteur du code du développeur est encore plus importante. Au-delà de la clarté qu’elle confère, cette séparation résout un problème majeur qui se produit lors de l’utilisation de DataSets typés dans Visual Studio 2002/2003.

Très souvent, vous souhaiterez étendre ou ajouter le code généré automatiquement pour le DataSet et ses classes associées ; par exemple, des propriétés supplémentaires ou du code de validation personnalisé. Vous pouvez continuer et les ajouter au code généré. Tout se passe bien tant que vous n’avez pas modifié le schéma et tant que vous ne devez pas régénérer le code du DataSet. Dans Visual Studio 2002/2003, dans la mesure où votre code est simplement ajouté au fichier avec le code généré, tout le code supplémentaire est supprimé lors de la régénération du code. Grâce à l’utilisation de classes partielles, cela ne se produit pas dans Visual Studio 2005. Le code nouvellement généré remplace le code concepteur existant dans le fichier avec l’extension .Designer.vb, mais le code écrit par le développeur dans le fichier .vb reste intact.

L’un des moyens d’étendre la fonctionnalité d’un DataSet avec des classes partielles consiste à ajouter du code de validation personnalisé. Cela permet d’ajouter une logique propre à l’application au DataSet typé généré. Ajoutons à présent une validation et une initialisation personnalisées à l’ajout d’une nouvelle ligne de la table Orders dans NorthwindDataSet. Lors de l’ajout d’une ligne, nous souhaitons vérifier si le code postal transmis correspond bien à la ville. Si tel n’est pas le cas, nous remplaçons la valeur du champ ShipPostalCode par Invalid. Supposons qu’une fonction renvoie True si le code postal correspond bien à la ville, comme suit :

Function IsPostalCodeInCity (ByVal PostalCode as string, ByVal City as string) As Boolean


Nous pouvons ajouter cette vérification à notre NorthwindDataSet en procédant de la façon suivante :

  1. Ouvrez le Concepteur de DataSet en sélectionnant Modifier le DataSet à l'aide du Concepteur dans la barre d'outils de la fenêtre Sources de données.

  2. Double-cliquez sur une zone vide à l’arrière-plan du concepteur. Le fichier NorthwindDataSet.vb est ainsi ouvert dans l’éditeur de code.

  3. Entrez le code suivant au lieu du code par défaut :

    Partial Public Class NorthwindDataSet
        Partial Class OrdersDataTable
            Protected Sub ValidateNewRow(ByVal sender As Object, _
                   ByVal e As System.Data.DataTableNewRowEventArgs) _
                   Handles Me.TableNewRow
                ' Create a strongly typed instance of the row
                ' This helps us avoid code in quotes, 
    ' eg, e.Row("ShipPostalCode")
                Dim ordersRow As NorthwindDataSet.OrdersRow
                ordersRow = e.Row
                If Not ordersRow.IsShipPostalCodeNull And _
                        Not ordersRow.IsShipCityNull Then
                    If Not IsPostalCodeInCity(ordersRow.ShipPostalCode, _
                            ordersRow.ShipCity) Then
                        ' Set the value of the Ship Postal Code
                        ordersRow.ShipPostalCode = "Invalid"
                        ' Typically, changing a users data is a bad user experience
      ' So indicate an error with the ErrorProvider
                        ' We are illustrating both approaches here
                        ordersRow.SetColumnError( _
                            ShipPostalCodeColumn.ColumnName, "Invalid Postal Code")
                    Else
                        ' we always need to reset the error when the value is valid
                        ordersRow.SetColumnError( _
                            ShipPostalCodeColumn.ColumnName, String.Empty)
                    End If
                End If
            End Sub
        End Class
    
        Private Shared Function IsPostalCodeInCity(ByVal postalCode As String, _
    ByVal city As String) As Boolean
            ' This is a stub, just to check functionality
            If city = "Rio de Janeiro" Then
                Return False
            Else
                Return True
            End If
        End Function
    End Class
    

Notez que toutes les classes associées du DataSet, telles que OrdersDataTable, sont implémentées en tant que classes imbriquées dans le DataSet. La déclaration de classe partielle illustrée dans le code précédent reflète cette implémentation.

Pour qu’une erreur soit indiquée par un fournisseur d’erreur, en plus ou à la place du remplacement du code postal par Invalid, procédez de la façon suivante :

  1. Faites glisser un contrôle Fournisseur d’erreur de la boîte à outils sur Form1 et faites-le glisser juste à droite de la zone de texte Ship Postal Code.

  2. Dans la fenêtre de propriétés du fournisseur d’erreur, affectez à la propriété DataSource la valeur OrdersBindingSource.

Exécutez l’application et accédez à un enregistrement dont la ville est Rio de Janeiro, afin de voir le code de validation en action, comme illustré figure 7.
newdtastvs05_fig7.gif
Figure 7. Contrôle de fournisseur d’erreur

Il s’agit simplement d’un exemple de la façon dont vous pouvez étendre la fonctionnalité du DataSet typé et les classes associées générées automatiquement par Visual Studio. Vous pouvez également ajouter des méthodes et propriétés aux classes générées. Lors de la conception de l’application et de votre utilisation des DataSets, vous découvrirez de nombreuses autres possibilités. L’essentiel à mémoriser est que dans Visual Studio 2005, grâce aux classes partielles, le code que vous écrivez se trouve dans un fichier distinct et n’est pas affecté par la régénération des classes DataSet.

Conclusion

L’utilisation des DataSets typés générés par Visual Studio 2005 n’a jamais été aussi facile et aussi flexible. Le Concepteur de DataSet offre un outil plus simple et plus naturel pour définir des DataSets. La nouvelle classe TableAdapter, configurable via le Concepteur de DataSet, offre un mécanisme centralisé unique pour gérer et exécuter facilement plusieurs requêtes et commandes sur une table de données spécifique. La fonctionnalité de compilateur de classe partielle permet la séparation complète entre le code généré par le concepteur et le code écrit par le développeur, ce qui permet la régénération des classes DataSet sans affecter le code personnalisé déjà écrit pour étendre ces classes. Enfin, les nouveaux mécanismes et classes de liaison de données .NET, associés aux outils de Visual Studio 2005, rendent plus simple et plus rapide le développement d’applications orientées données.

MMerci à Steve Lasker, ainsi qu’à Alan Griver et Pablo Castro de Microsoft pour leur aide dans la préparation de cet article.

A propos de l'auteur

Jackie Goldstein est responsable de leave-ms.gif Renaissance Computer Systems, spécialisé dans le consulting, la formation et le développement au moyen des outils et technologies Microsoft. Jackie est directeur régional Microsoft, fondateur du groupe des utilisateurs de Visual Basic en Israël et il intervient lors de certains événements internationaux destinés aux développeurs, tels que TechEd, VSLive!, Developer Days et Microsoft PDC. Il est également l'auteur de l'ouvrage leave-ms.gif Database Access with Visual Basic.NET (Addison-Wesley, ISBN 0-67232-3435) et membre de l'INETA Speakers Bureau. En décembre 2003, Microsoft l'a nommé « .NET Software Legend ».

Afficher:
© 2014 Microsoft