Partager via


Mise à jour du TableAdapter pour l’utilisation de jointures (VB)

par Scott Mitchell

Télécharger le PDF

Lors de l’utilisation d’une base de données, il est courant de demander des données réparties sur plusieurs tables. Pour récupérer des données à partir de deux tables différentes, nous pouvons utiliser une sous-requête corrélée ou une opération JOIN. Dans ce tutoriel, nous comparons les sous-requêtes corrélées et la syntaxe JOIN avant de voir comment créer un TableAdapter qui inclut une jointure dans sa requête principale.

Présentation

Avec les bases de données relationnelles, les données qui nous intéressent sont souvent réparties entre plusieurs tables. Par exemple, lors de l’affichage des informations sur le produit, nous souhaitons probablement répertorier les noms de chaque catégorie et nom de fournisseur correspondants. La table Products comporte des valeurs CategoryID et SupplierID, mais les noms réels des catégories et des fournisseurs se trouvent respectivement dans la table Categories et la table Suppliers.

Pour récupérer des informations d’une autre table associée, nous pouvons utiliser des sous-requêtes corrélées ou JOINs. Une sous-requête corrélée est une requête imbriquée SELECT qui fait référence à des colonnes dans la requête externe. Par exemple, dans le didacticiel Création d’une couche d’accès aux données , nous avons utilisé deux sous-requêtes corrélées dans la ProductsTableAdapter requête principale pour retourner les noms de catégorie et de fournisseur pour chaque produit. A JOIN est une construction SQL qui fusionne les lignes associées à partir de deux tables différentes. Nous avons utilisé une JOIN dans le didacticiel Interroger des données avec le didacticiel SqlDataSource Control pour afficher des informations de catégorie en même temps que chaque produit.

La raison pour laquelle nous avons évité d'utiliser JOIN s avec les TableAdapters est en raison des limitations de l'Assistant TableAdapter pour générer automatiquement les instructions correspondantes INSERT, UPDATE, et DELETE. Plus précisément, si la requête principale de TableAdapter contient des JOIN, TableAdapter ne peut pas créer automatiquement les instructions SQL ad hoc ou les procédures stockées pour ses propriétés InsertCommand, UpdateCommand, et DeleteCommand.

Dans ce tutoriel, nous allons brièvement comparer et contraster les sous-requêtes corrélées et JOIN avant d’explorer comment créer un TableAdapter qui inclut des JOIN dans sa requête principale.

Comparaison et contraste des sous-requêtes etJOIN des sous-requêtes corrélées

Rappelez-vous que le ProductsTableAdapter créé dans le premier tutoriel le Northwind DataSet utilise des sous-requêtes corrélées pour obtenir, pour chaque produit, sa catégorie et le nom du fournisseur correspondant. La ProductsTableAdapter requête principale est illustrée ci-dessous.

SELECT ProductID, ProductName, SupplierID, CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = 
            Products.CategoryID) as CategoryName, 
       (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = 
            Products.SupplierID) as SupplierName
FROM Products

Les deux sous-requêtes corrélées - (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) et (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) - sont des requêtes SELECT qui retournent une valeur unique par produit en tant que colonne supplémentaire dans la liste de colonnes de l’instruction externe SELECT.

Vous pouvez également utiliser une JOIN option pour retourner le nom du fournisseur et de la catégorie de chaque produit. La requête suivante retourne la même sortie que celle ci-dessus, mais utilise JOIN à la place des sous-requêtes.

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

Une JOIN fusion des enregistrements d’une table avec des enregistrements d’une autre table en fonction de certains critères. Dans la requête ci-dessus, par exemple, l’instruction LEFT JOIN Categories ON Categories.CategoryID = Products.CategoryID est destinée à SQL Server pour fusionner chaque enregistrement de produit avec l’enregistrement de catégorie dans laquelle la valeur CategoryID correspond à la valeur CategoryID du produit. Le résultat fusionné nous permet d’utiliser les champs de catégorie correspondants pour chaque produit (par CategoryNameexemple).

Remarque

JOIN sont couramment utilisés lors de l’interrogation de données à partir de bases de données relationnelles. Si vous débutez avec la syntaxe JOIN ou si vous avez besoin de vous rafraîchir un peu la mémoire sur son utilisation, je recommande le didacticiel de jointure SQL sur W3 Schools. Vous pouvez également lire les JOIN sections Principes fondamentaux et Principes de base de la sous-requête de la documentation en ligne de SQL.

Étant donné que les sous-requêtes JOIN et les sous-requêtes corrélées peuvent être utilisées pour récupérer des données associées à partir d’autres tables, de nombreux développeurs se retrouvent à se gratter la tête et se demandent quelle approche utiliser. Tous les gourous SQL à qui j’ai parlé ont dit à peu près la même chose, que cela ne change pas vraiment les performances, car SQL Server produira des plans d'exécution presque identiques. Leur conseil, alors, est d’utiliser la technique que vous et votre équipe êtes le plus à l’aise avec. Il mérite de noter qu’après avoir transmis ces conseils, ces experts expriment immédiatement leur préférence de JOIN s’exprimer sur les sous-requêtes corrélées.

Lors de la création d’une couche d’accès aux données à l’aide de Jeux de données typés, les outils fonctionnent mieux lors de l’utilisation de sous-requêtes. En particulier, l'Assistant TableAdapter ne génère pas automatiquement les instructions correspondantes INSERT, UPDATE et DELETE si la requête principale contient des JOIN, mais génère automatiquement ces instructions lorsque des sous-requêtes corrélées sont utilisées.

Pour explorer cette lacune, créez un Jeu de données typé temporaire dans le ~/App_Code/DAL dossier. Pendant l’Assistant Configuration de TableAdapter, choisissez d’utiliser des instructions SQL ad hoc et saisissez la requête suivante SELECT (voir Figure 1) :

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

Capture d’écran montrant la fenêtre de l’Assistant de Configuration de TableAdaptor avec une requête entrée qui contient des jointures.

Figure 1 : Entrer une requête principale contenant JOIN des éléments (cliquez pour afficher l’image de taille complète)

Par défaut, TableAdapter créera automatiquement les instructions pour INSERT, UPDATE et DELETE basées sur la requête principale. Si vous cliquez sur le bouton Avancé, vous pouvez voir que cette fonctionnalité est activée. Malgré ce paramètre, le TableAdapter ne pourra pas créer les instructions INSERT, UPDATE, et DELETE car la requête principale contient un JOIN.

Capture d’écran montrant la fenêtre Options avancées avec la case à cocher Générer des instructions Insert, Update and Delete cochée.

Figure 2 : Entrer une requête principale qui contient JOIN s

Cliquez sur Terminer pour finaliser l'Assistant. À ce stade, votre Concepteur DataSet inclut un seul TableAdapter avec un DataTable contenant des colonnes correspondant à chacun des champs retournés dans la liste des colonnes de la requête SELECT. Cela inclut le CategoryName et le SupplierName, comme le montre la figure 3.

DataTable inclut une colonne pour chaque champ retourné dans la liste des colonnes

Figure 3 : DataTable inclut une colonne pour chaque champ retourné dans la liste des colonnes

Bien que DataTable ait les colonnes appropriées, TableAdapter manque de valeurs pour ses propriétés InsertCommand, UpdateCommand, et DeleteCommand. Pour confirmer cela, cliquez sur TableAdapter dans le Concepteur, puis accédez à la fenêtre Propriétés. Vous verrez que les propriétés InsertCommand, UpdateCommand et DeleteCommand sont définies sur (Aucun).

Les propriétés InsertCommand, UpdateCommand et DeleteCommand sont définies sur (Aucun)

Figure 4 : Les propriétés InsertCommand, UpdateCommand et DeleteCommand sont définies sur (Aucun) (Cliquez pour afficher l’image de taille complète)

Pour contourner cette lacune, nous pouvons fournir manuellement les instructions et paramètres SQL pour les propriétés InsertCommand, UpdateCommand, et DeleteCommand via la fenêtre Propriétés. Nous pourrions également commencer par configurer la requête principale du TableAdapter afin de ne pas inclure de JOIN. Cela permettra aux instructions INSERT, UPDATE et DELETE d'être générées automatiquement pour nous. Une fois l’Assistant terminé, nous pourrions ensuite mettre à jour manuellement les TableAdapters SelectCommand à partir de la fenêtre Propriétés afin qu'ils incluent la syntaxe JOIN.

Bien que cette approche fonctionne, elle est très fragile lors de l’utilisation de requêtes SQL ad hoc, car chaque fois que la requête principale de TableAdapter est reconfigurée via l’Assistant, les instructions INSERT, UPDATE, et DELETE générées automatiquement sont recréées. Cela signifie que toutes les personnalisations que nous avons effectuées ultérieurement seraient perdues si nous avons cliqué avec le bouton droit sur TableAdapter, choisi Configurer à partir du menu contextuel et terminé à nouveau l’Assistant.

La fragilité des instructions générées INSERTautomatiquement par TableAdapter, UPDATEet les DELETE instructions sont, heureusement, limitées aux instructions SQL ad hoc. Si votre TableAdapter utilise des procédures stockées, vous pouvez personnaliser les procédures stockées SelectCommand, InsertCommand, UpdateCommand ou DeleteCommand et réexécuter l’Assistant Configuration de TableAdapter sans craindre que les procédures stockées ne soient modifiées.

Au cours des prochaines étapes, nous allons créer un TableAdapter qui, dans un premier temps, utilise une requête principale omettant les éléments JOIN, afin que les procédures stockées d'insertion, de mise à jour et de suppression correspondantes soient générées automatiquement. Nous allons ensuite mettre à jour ce SelectCommand afin qu'il utilise un JOIN qui retourne des colonnes supplémentaires à partir de tables associées. Enfin, nous allons créer une classe de couche logique métier correspondante et illustrer l’utilisation de TableAdapter dans une page web ASP.NET.

Étape 1 : Création de TableAdapter à l’aide d’une requête principale simplifiée

Pour ce didacticiel, nous allons ajouter un TableAdapter et un DataTable fortement typé pour la table Employees dans le DataSet NorthwindWithSprocs. La Employees table contient un ReportsTo champ qui spécifie le EmployeeID du responsable de l'employé. Par exemple, l'employée Anne Dodsworth a une ReportTo valeur de 5, qui est la EmployeeID de Steven Buchanan. Par conséquent, Anne signale à Steven, son manager. En plus de signaler la valeur de ReportsTo chaque employé, nous pourrions également récupérer le nom de son responsable. Cette opération peut être effectuée à l’aide d’un JOIN. Toutefois, l’utilisation d’un élément JOIN lors de la création initiale d’un TableAdapter empêche l’Assistant de générer automatiquement les fonctionnalités d’insertion, de mise à jour et de suppression correspondantes. Par conséquent, nous allons commencer par créer un TableAdapter dont la requête principale ne contient pas de JOIN. Ensuite, à l’étape 2, nous allons mettre à jour la procédure stockée principale de requête pour récupérer le nom du gestionnaire via un JOIN.

Commencez par ouvrir le NorthwindWithSprocs DataSet dans le ~/App_Code/DAL dossier. Cliquez avec le bouton droit sur le Concepteur, sélectionnez l’option Ajouter dans le menu contextuel, puis sélectionnez l’élément de menu TableAdapter. Cette opération lance l’Assistant Configuration de TableAdapter. Comme le montre la figure 5, demandez à l’Assistant de créer de nouvelles procédures stockées, puis cliquez sur Suivant. Pour un rafraîchissement sur la création de nouvelles procédures stockées à partir de l'assistant TableAdapter, consultez le didacticiel Création de nouvelles procédures stockées pour les TableAdapters du DataSet typé.

Sélectionnez l’option Créer de nouvelles procédures stockées

Figure 5 : Sélectionnez l’option Créer de nouvelles procédures stockées (cliquez pour afficher l’image de taille complète)

Utilisez l’instruction suivante SELECT pour la requête principale de TableAdapter :

SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country
FROM Employees

Étant donné que cette requête n’inclut pas de JOIN, l’Assistant TableAdapter crée automatiquement des procédures stockées avec des instructions correspondantes INSERT, UPDATE, et DELETE, ainsi qu’une procédure stockée pour l’exécution de la requête principale.

L’étape suivante nous permet de nommer les procédures stockées de TableAdapter. Utilisez les noms Employees_Select, , Employees_InsertEmployees_Updateet Employees_Delete, comme illustré dans la figure 6.

Nommer les procédures stockées de TableAdapter

Figure 6 : Nommer les procédures stockées de TableAdapter (cliquez pour afficher l’image de taille complète)

L’étape finale nous invite à nommer les méthodes de TableAdapter. Utilisez Fill et GetEmployees en tant que noms de méthode. Veillez également à ce que la case à cocher pour les méthodes Create (GenerateDBDirectMethods), qui envoient des mises à jour directement à la base de données, reste cochée.

Nommez les méthodes TableAdapter Fill et GetEmployees

Figure 7 : Nommer les méthodes Fill de TableAdapter et GetEmployees (Cliquez pour afficher l’image de taille complète)

Une fois l’Assistant terminé, prenez un moment pour examiner les procédures stockées dans la base de données. Vous devriez voir quatre nouvelles : Employees_Select, , Employees_InsertEmployees_Update, et Employees_Delete. Ensuite, inspectez le EmployeesDataTable et le EmployeesTableAdapter qui viennent d'être créés. DataTable contient une colonne pour chaque champ retourné par la requête principale. Cliquez sur TableAdapter, puis accédez à la fenêtre Propriétés. Vous verrez que les propriétés InsertCommand, UpdateCommand et DeleteCommand sont correctement configurées pour appeler les procédures stockées correspondantes.

TableAdapter inclut des fonctionnalités d’insertion, de mise à jour et de suppression

Figure 8 : TableAdapter inclut les fonctionnalités d’insertion, de mise à jour et de suppression (cliquez pour afficher l’image de taille complète)

Lorsque les procédures stockées pour l'insertion, la mise à jour et la suppression sont créées automatiquement et que les propriétés InsertCommand, UpdateCommand, et DeleteCommand sont correctement configurées, nous sommes prêts à personnaliser la procédure stockée SelectCommand pour retourner des informations supplémentaires sur chaque responsable de l'employé. Plus précisément, nous devons mettre à jour la Employees_Select procédure stockée pour utiliser un JOIN et retourner les valeurs FirstName et LastName du gestionnaire. Une fois la procédure stockée mise à jour, nous devons mettre à jour le DataTable afin qu’il inclut ces colonnes supplémentaires. Nous aborderons ces deux tâches dans les étapes 2 et 3.

Étape 2 : Personnalisation de la procédure stockée pour inclure unJOIN

Commencez par accéder à l’Explorateur de serveurs, en explorant le dossier Procédures stockées de la base de données Northwind et en ouvrant la Employees_Select procédure stockée. Si vous ne voyez pas cette procédure stockée, cliquez avec le bouton droit sur le dossier Procédures stockées et choisissez Actualiser. Mettez à jour la procédure stockée afin qu’elle utilise un LEFT JOIN pour renvoyer le prénom et le nom du gestionnaire :

SELECT Employees.EmployeeID, Employees.LastName, 
       Employees.FirstName, Employees.Title, 
       Employees.HireDate, Employees.ReportsTo, 
       Employees.Country,
       Manager.FirstName as ManagerFirstName, 
       Manager.LastName as ManagerLastName
FROM Employees
    LEFT JOIN Employees AS Manager ON
        Employees.ReportsTo = Manager.EmployeeID

Après avoir mis à jour l’instruction SELECT , enregistrez les modifications en accédant au menu Fichier et en choisissant Enregistrer Employees_Select. Vous pouvez également cliquer sur l’icône Enregistrer dans la barre d’outils ou appuyer sur Ctrl+S. Après avoir enregistré vos modifications, cliquez avec le bouton droit sur la Employees_Select procédure stockée dans l’Explorateur de serveurs et choisissez Exécuter. Cette opération exécute la procédure stockée et affiche ses résultats dans la fenêtre Sortie (voir la figure 9).

Les résultats des procédures stockées sont affichés dans la fenêtre sortie

Figure 9 : Les résultats des procédures stockées sont affichés dans la fenêtre sortie (cliquez pour afficher l’image de taille complète)

Étape 3 : Mise à jour des colonnes de DataTable

À ce stade, la Employees_Select procédure stockée retourne les valeurs ManagerFirstName et ManagerLastName, mais ces colonnes manquent dans le EmployeesDataTable. Ces colonnes manquantes peuvent être ajoutées à DataTable de deux façons :

  • Manuellement : cliquez avec le bouton droit sur dataTable dans le Concepteur DataSet et, dans le menu Ajouter, choisissez Colonne. Vous pouvez ensuite nommer la colonne et définir ses propriétés en conséquence.
  • Automatiquement : l’Assistant Configuration de TableAdapter met à jour les colonnes de DataTable pour refléter les champs retournés par la SelectCommand procédure stockée. Lors de l’utilisation d’instructions SQL ad hoc, l’Assistant supprime également les propriétés InsertCommand, UpdateCommand, et DeleteCommand puisque le SelectCommand contient maintenant un JOIN. Toutefois, lors de l’utilisation de procédures stockées, ces propriétés de commande restent intactes.

Nous avons exploré manuellement l’ajout de colonnes DataTable dans les didacticiels précédents, notamment Master/Detail Using a Bulleted List of Master Records with a Details DataList and Uploading Files, et nous allons examiner ce processus plus en détail dans notre prochain tutoriel. Pour ce tutoriel, nous allons toutefois utiliser l’approche automatique via l’Assistant Configuration de TableAdapter.

Commencez par cliquer avec le bouton droit sur EmployeesTableAdapter et sélectionnez Configurer dans le menu contextuel. Cela affiche l’Assistant Configuration de TableAdapter, qui répertorie les procédures stockées utilisées pour sélectionner, insérer, mettre à jour et supprimer, ainsi que leurs valeurs et paramètres de retour (le cas échéant). La figure 10 montre cet Assistant. Ici, nous pouvons voir que la Employees_Select procédure stockée retourne maintenant les champs ManagerFirstName et ManagerLastName.

L’Assistant affiche la liste de colonnes mise à jour pour la procédure stockée Employees_Select

Figure 10 : L’Assistant affiche la liste de colonnes mise à jour de la Employees_Select procédure stockée (cliquez pour afficher l’image de taille complète)

Terminez l’Assistant en cliquant sur Terminer. Après être retourné(e) au Concepteur DataSet, EmployeesDataTable inclut deux colonnes supplémentaires : ManagerFirstName et ManagerLastName.

EmployeesDataTable contient deux nouvelles colonnes

Figure 11 : Contient EmployeesDataTable deux nouvelles colonnes (cliquez pour afficher l’image de taille complète)

Pour illustrer que la procédure stockée mise à jour Employees_Select est en vigueur et que les fonctionnalités d’insertion, de mise à jour et de suppression de TableAdapter sont toujours fonctionnelles, nous allons créer une page web qui permet aux utilisateurs d’afficher et de supprimer des employés. Avant de créer une telle page, toutefois, nous devons d’abord créer une classe dans la couche logique métier pour travailler avec les employés du NorthwindWithSprocs DataSet. À l’étape 4, nous allons créer une EmployeesBLLWithSprocs classe. À l’étape 5, nous allons utiliser cette classe à partir d’une page ASP.NET.

Étape 4 : Implémentation de la couche logique métier

Créez un fichier de classe dans le ~/App_Code/BLL dossier nommé EmployeesBLLWithSprocs.vb. Cette classe imite la sémantique de la classe existante EmployeesBLL , seule cette nouvelle méthode fournit moins de méthodes et utilise le NorthwindWithSprocs DataSet (au lieu de Northwind DataSet). Ajoutez le code suivant à la classe EmployeesBLLWithSprocs .

Imports NorthwindWithSprocsTableAdapters
<System.ComponentModel.DataObject()> _
Public Class EmployeesBLLWithSprocs
    Private _employeesAdapter As EmployeesTableAdapter = Nothing
    Protected ReadOnly Property Adapter() As EmployeesTableAdapter
        Get
            If _employeesAdapter Is Nothing Then
                _employeesAdapter = New EmployeesTableAdapter()
            End If
            Return _employeesAdapter
        End Get
    End Property
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Function GetEmployees() As NorthwindWithSprocs.EmployeesDataTable
        Return Adapter.GetEmployees()
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Delete, True)> _
    Public Function DeleteEmployee(ByVal employeeID As Integer) As Boolean
        Dim rowsAffected = Adapter.Delete(employeeID)
        'Return true if precisely one row was deleted, otherwise false
        Return rowsAffected = 1
    End Function
End Class

La EmployeesBLLWithSprocs propriété Adapter de la classe retourne une instance de NorthwindWithSprocs DataSet EmployeesTableAdapter. Cela est utilisé par la classe GetEmployees et les méthodes DeleteEmployee. La méthode GetEmployees appelle la méthode correspondante EmployeesTableAdapter, qui invoque la procédure stockée GetEmployees et où les résultats sont enregistrés dans un Employees_Select. La méthode DeleteEmployee appelle de même la méthode EmployeesTableAdapter, qui invoque la procédure stockée Delete.

Étape 5 : Utilisation des données dans la couche Présentation

Une fois la EmployeesBLLWithSprocs classe terminée, nous sommes prêts à travailler avec les données des employés via une page ASP.NET. Ouvrez la page JOINs.aspx dans le dossier AdvancedDAL et faites glisser un GridView à partir de la boîte à outils vers le Concepteur, en définissant sa propriété ID sur Employees. Ensuite, à partir de la balise active gridView, liez la grille à un nouveau contrôle ObjectDataSource nommé EmployeesDataSource.

Configurez l'ObjectDataSource pour utiliser la classe EmployeesBLLWithSprocs et, à partir des onglets SELECT et DELETE, assurez-vous que les méthodes GetEmployees et DeleteEmployee sont sélectionnées dans les listes déroulantes. Cliquez sur Terminer pour terminer la configuration de ObjectDataSource.

Configurer ObjectDataSource pour utiliser la classe EmployeesBLLWithSprocs

Figure 12 : Configurer ObjectDataSource pour utiliser la classe (EmployeesBLLWithSprocs de taille complète)

Faites en sorte qu'ObjectDataSource utilise les méthodes GetEmployees et DeleteEmployee

Figure 13 : Faire Utiliser ObjectDataSource avec les méthodes GetEmployees et DeleteEmployee (Cliquez pour afficher l’image en taille réelle)

Visual Studio ajoute un Objet BoundField à GridView pour chacune des EmployeesDataTable colonnes. Supprimez tous ces BoundFields à l’exception de Title, LastName, FirstName, ManagerFirstName, et ManagerLastName, et renommez les propriétés HeaderText des quatre derniers BoundFields en Nom, Prénom, Prénom du Gestionnaire, et Nom du Gestionnaire, respectivement.

Pour permettre aux utilisateurs de supprimer des employés de cette page, nous devons effectuer deux opérations. Tout d’abord, demandez à GridView de fournir des fonctionnalités de suppression en cochant l’option Activer la suppression à partir de sa balise active. Ensuite, modifiez la propriété ObjectDataSource de la valeur définie par l’Assistant ObjectDataSource (OldValuesParameterFormatString) à sa valeur par défaut (original_{0}). Après avoir apporté ces modifications, votre balisage déclaratif GridView et ObjectDataSource doit ressembler à ce qui suit :

<asp:GridView ID="Employees" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="EmployeeID" DataSourceID="EmployeesDataSource">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        <asp:BoundField DataField="Title" 
            HeaderText="Title" 
            SortExpression="Title" />
        <asp:BoundField DataField="LastName" 
            HeaderText="Last Name" 
            SortExpression="LastName" />
        <asp:BoundField DataField="FirstName" 
            HeaderText="First Name" 
            SortExpression="FirstName" />
        <asp:BoundField DataField="ManagerFirstName" 
            HeaderText="Manager's First Name" 
            SortExpression="ManagerFirstName" />
        <asp:BoundField DataField="ManagerLastName" 
            HeaderText="Manager's Last Name" 
            SortExpression="ManagerLastName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="EmployeesDataSource" runat="server" 
    DeleteMethod="DeleteEmployee" OldValuesParameterFormatString="{0}" 
    SelectMethod="GetEmployees" TypeName="EmployeesBLLWithSprocs">
    <DeleteParameters>
        <asp:Parameter Name="employeeID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Testez la page en la visitant via un navigateur. Comme le montre la figure 14, la page répertorie chaque employé et son nom de responsable (en supposant qu’ils en ont un).

La jointure dans la procédure stockée Employees_Select retourne le nom du gestionnaire

Figure 14 : La JOINEmployees_Select procédure stockée renvoie le nom du gestionnaire (cliquez pour afficher l’image de taille complète)

Cliquez sur le bouton Supprimer pour démarrer le flux de travail de suppression, ce qui aboutit à l’exécution de la Employees_Delete procédure stockée. Toutefois, l’instruction tentée DELETE dans la procédure stockée échoue en raison d’une violation de contrainte de clé étrangère (voir la figure 15). Plus précisément, chaque employé a un ou plusieurs enregistrements dans la Orders table, ce qui entraîne l’échec de la suppression.

La suppression d’un employé ayant des commandes correspondantes entraîne une violation de contrainte de clé étrangère

Figure 15 : La suppression d’un employé disposant de commandes correspondantes entraîne une violation de contrainte de clé étrangère (cliquez pour afficher l’image de taille complète)

Pour permettre à un employé d’être supprimé, vous pouvez :

  • Mettez à jour la contrainte de clé étrangère pour effectuer un effacement en cascade.
  • Supprimez manuellement les enregistrements de la Orders table pour les employés que vous souhaitez supprimer, ou
  • Mettez à jour la Employees_Delete procédure stockée pour supprimer d’abord les enregistrements associés de la Orders table avant de supprimer l’enregistrement Employees . Nous avons abordé cette technique dans le didacticiel Utilisation de procédures stockées existantes pour les TableAdapters des Typed DataSets.

Je laisse ça comme un exercice pour le lecteur.

Résumé

Lorsque vous utilisez des bases de données relationnelles, il est courant que les requêtes extrayent leurs données à partir de plusieurs tables associées. Les sous-requêtes corrélées et JOIN s fournissent deux techniques différentes pour accéder aux données à partir de tables associées dans une requête. Dans les didacticiels précédents, nous avons généralement utilisé des sous-requêtes corrélées, car TableAdapter ne peut pas générer automatiquement les instructions INSERT, UPDATE, et DELETE pour les requêtes impliquant des JOINs. Bien que ces valeurs puissent être fournies manuellement, lorsque vous utilisez des instructions SQL ad hoc, toutes les personnalisations seront remplacées une fois que l'Assistant de Configuration de TableAdapter aura été terminé.

Heureusement, Les TableAdapters créés à l’aide de procédures stockées ne souffrent pas de la même fragilité que celles créées à l’aide d’instructions SQL ad hoc. Par conséquent, il est possible de créer un TableAdapter dont la requête principale utilise une JOIN lors de l’utilisation de procédures stockées. Dans ce tutoriel, nous avons vu comment créer un tel TableAdapter. Nous avons commencé à utiliser une requête sans JOIN pour la requête principale du TableAdapter, afin que les procédures d'insertion, de mise à jour et de suppression correspondantes soient automatiquement créées SELECT. Une fois la configuration initiale de TableAdapter terminée, nous avons modifié la SelectCommand procédure stockée pour utiliser un JOIN et réexécuté l'assistant de configuration de TableAdapter pour mettre à jour les colonnes de EmployeesDataTable.

En réexécutant l’Assistant de Configuration TableAdapter, les colonnes EmployeesDataTable ont été automatiquement mises à jour pour refléter les champs de données retournés par la procédure stockée Employees_Select. Sinon, nous pourrions avoir ajouté ces colonnes manuellement à DataTable. Nous allons explorer manuellement l’ajout de colonnes au DataTable dans le tutoriel suivant.

Bonne programmation !

À propos de l’auteur

Scott Mitchell, auteur de sept livres ASP/ASP.NET et fondateur de 4GuysFromRolla.com, travaille avec les technologies Web Microsoft depuis 1998. Scott travaille en tant que consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 2.0 en 24 heures. On peut le joindre à mitchell@4GuysFromRolla.com.

Merci spécial à

Cette série de tutoriels a été examinée par de nombreux réviseurs utiles. Les réviseurs principaux de ce tutoriel étaient Hilton Geisenow, David Suru et Teresa Murphy. Vous souhaitez consulter mes prochains articles MSDN ? Si c’est le cas, déposez-moi une ligne à mitchell@4GuysFromRolla.com.