Partager via


Mise à jour hiérarchique dans le développement .NET Framework

Remarque

La DataSet classe et les classes associées sont des technologies .NET Framework héritées du début des années 2000 qui permettent aux applications d’utiliser des données en mémoire pendant que les applications sont déconnectées de la base de données. Les technologies sont particulièrement utiles pour les applications qui permettent aux utilisateurs de modifier les données et de conserver les modifications apportées à la base de données. Bien que les jeux de données soient une technologie éprouvée, l’approche recommandée pour les nouvelles applications .NET consiste à utiliser Entity Framework Core. Entity Framework offre un moyen plus naturel d’utiliser des données tabulaires en tant que modèles objet et dispose d’une interface de programmation plus simple.

La mise à jour hiérarchique fait référence au processus d’enregistrement des données mises à jour (à partir d’un jeu de données avec deux tables associées) vers une base de données tout en conservant les règles d’intégrité référentielle. L’intégrité référentielle fait référence aux règles de cohérence fournies par les contraintes d’une base de données qui contrôlent le comportement d’insertion, de mise à jour et de suppression d’enregistrements associés. Par exemple, c'est l'intégrité référentielle qui impose la création d’un enregistrement client avant d’autoriser la création de commandes pour ce client. Pour plus d’informations sur les relations dans les jeux de données, consultez Relations dans les jeux de données.

La fonctionnalité de mise à jour hiérarchique utilise un TableAdapterManager pour gérer les TableAdapters dans un jeu de données typé. Le TableAdapterManager composant est une classe générée par Visual Studio, et non un type .NET. Lorsque vous faites glisser une table de la fenêtre Sources de données vers une page Windows Form ou WPF, Visual Studio ajoute une variable de type TableAdapterManager au formulaire ou à la page, et vous le voyez dans le concepteur dans la barre d’état du composant. Pour plus d’informations sur la TableAdapterManager classe, consultez la section Référence de TableAdapterManager de TableAdapters.

Par défaut, un jeu de données traite les tables associées comme des « relations uniquement », ce qui signifie qu’il n’applique pas les contraintes de clé étrangère. Vous pouvez modifier ce paramètre au moment du design à l’aide du Concepteur de jeux de données. Sélectionnez la ligne de relation entre deux tables pour afficher la boîte de dialogue Relation . Les modifications que vous apportez ici détermineront le comportement du TableAdapterManager quand il envoie les modifications dans les tables associées à la base de données.

Activer la mise à jour hiérarchique dans un jeu de données

Par défaut, la mise à jour hiérarchique est activée pour tous les nouveaux jeux de données ajoutés ou créés dans un projet. Activez ou désactivez la mise à jour hiérarchique en définissant la propriété De mise à jour hiérarchique d’un jeu de données typé dans le jeu de données sur True ou False :

Paramètre de mise à jour hiérarchique

Créer une relation entre les tables

Pour créer une relation entre deux tables, dans le Concepteur de jeux de données, sélectionnez la barre de titre de chaque table, puis cliquez avec le bouton droit et sélectionnez Ajouter une relation.

Menu de mise à jour hiérarchique pour ajouter une relation

Comprendre les contraintes de clé étrangère, les mises à jour en cascade et les suppressions

Il est important de comprendre comment les contraintes de clé étrangère et le comportement en cascade dans la base de données sont créés dans le code de jeu de données généré.

Par défaut, les tables de données d’un jeu de données sont générées avec des relations (DataRelation) qui correspondent aux relations dans la base de données. Toutefois, la relation dans le jeu de données n’est pas générée comme une contrainte de clé étrangère. La DataRelation est configurée comme une Relation uniquement sans UpdateRule ou DeleteRule en vigueur.

Par défaut, les mises à jour en cascade et les suppressions en cascade sont désactivées même si la relation de base de données est définie avec des mises à jour en cascade ou des suppressions en cascade activées. Par exemple, la création d’un client et d’une nouvelle commande, puis la tentative d’enregistrement des données peut entraîner un conflit avec les contraintes de clé étrangère définies dans la base de données. Pour plus d’informations, consultez Désactiver les contraintes lors du remplissage d’un jeu de données.

Définir l’ordre d’exécution des mises à jour

La définition de l’ordre d’exécution des mises à jour définit l’ordre des insertions, mises à jour et suppressions individuelles requises pour enregistrer toutes les données modifiées dans toutes les tables d’un jeu de données. Lorsque la mise à jour hiérarchique est activée, les insertions sont effectuées en premier, puis les mises à jour, puis les suppressions. TableAdapterManager fournit une propriété UpdateOrder qui peut être définie pour effectuer des mises à jour, puis des insertions, puis des suppressions.

Remarque

Il est important de comprendre que l’ordre de mise à jour est inclusif. Autrement dit, lorsque les mises à jour sont effectuées, les insertions et les suppressions sont effectuées pour toutes les tables du jeu de données.

Pour définir la UpdateOrder propriété, après avoir fait glisser des éléments de la fenêtre Sources de données vers un formulaire, sélectionnez l’élément TableAdapterManager dans la barre d’état du composant, puis définissez la UpdateOrder propriété dans la fenêtre Propriétés .

Créer une copie de sauvegarde d’un jeu de données avant d’effectuer une mise à jour hiérarchique

Lorsque vous enregistrez des données (en appelant la méthode TableAdapterManager.UpdateAll()), le TableAdapterManager tente de mettre à jour les données pour chaque table dans une seule transaction. Si une partie de la mise à jour d'une table échoue, toute la transaction est annulée. Dans la plupart des cas, le rollback ramène votre application à son état d'origine.

Toutefois, vous pouvez parfois restaurer le jeu de données à partir de la copie de sauvegarde. Un exemple de ceci peut se produire lorsque vous utilisez des valeurs d’incrémentation automatique. Par exemple, si une opération d’enregistrement ne réussit pas, les valeurs d’incrément automatique ne sont pas réinitialisées dans le jeu de données et le jeu de données continue de créer des valeurs d’incrémentation automatique. Cela laisse un écart dans la numérotation qui peut ne pas être acceptable dans votre application. Dans les situations où il s’agit d’un problème, la TableAdapterManager propriété fournit une BackupDataSetBeforeUpdate propriété qui remplace le jeu de données existant par une copie de sauvegarde en cas d’échec de la transaction.

Remarque

La copie de sauvegarde est uniquement en mémoire pendant l’exécution de la TableAdapterManager.UpdateAll méthode. Par conséquent, il n’y a pas d’accès programmatique à ce jeu de données de sauvegarde, car il remplace le jeu de données d’origine, ou sort de l’étendue dès que l’exécution de la méthode TableAdapterManager.UpdateAll est terminée.

Modifier le code d’enregistrement généré pour effectuer la mise à jour hiérarchique

Enregistrez les modifications des tables de données associées dans le jeu de données dans la base de données en appelant la TableAdapterManager.UpdateAll méthode et en transmettant le nom du jeu de données qui contient les tables associées. Par exemple, exécutez la TableAdapterManager.UpdateAll(NorthwindDataset) méthode pour envoyer des mises à jour de toutes les tables de NorthwindDataset à la base de données principale.

Après avoir supprimé les éléments de la fenêtre Sources de données , le code est automatiquement ajouté à l’événement Form_Load pour remplir chaque table (les TableAdapter.Fill méthodes). Du code est également ajouté à l'événement de clic du bouton Enregistrer du BindingNavigator pour enregistrer les données de l'ensemble de données dans la base de données (la méthode TableAdapterManager.UpdateAll).

Le code d’enregistrement généré contient également une ligne de code qui appelle la CustomersBindingSource.EndEdit méthode. Plus particulièrement, elle appelle la méthode EndEdit du premier BindingSource ajouté au formulaire. En d’autres termes, ce code est généré uniquement pour la première table qui est déplacée de la fenêtre Sources de données vers le formulaire. L’appel EndEdit valide toutes les modifications qui sont en cours de traitement dans tous les contrôles liés aux données en cours de modification. Par conséquent, si un contrôle lié aux données a toujours le focus et que vous cliquez sur le bouton Enregistrer, toutes les modifications en attente dans ce contrôle sont validées avant l’enregistrement réel (méthode TableAdapterManager.UpdateAll).

Remarque

Le Concepteur de jeux de données ajoute uniquement le BindingSource.EndEdit code pour la première table qui est déposée sur le formulaire. Par conséquent, vous devez ajouter une ligne de code pour appeler la BindingSource.EndEdit méthode pour chaque table associée sur le formulaire. Dans cette procédure pas à pas, cela signifie que vous devez ajouter un appel à la méthode OrdersBindingSource.EndEdit.

  1. Double-cliquez sur le bouton Enregistrer dans l’éditeur BindingNavigator de code pour ouvrir Form1 .

  2. Ajoutez une ligne de code pour appeler la OrdersBindingSource.EndEdit méthode après la ligne qui appelle la CustomersBindingSource.EndEdit méthode. Le code de l’événement de clic du bouton Enregistrer doit ressembler à ce qui suit :

    this.Validate();
    this.customersBindingSource.EndEdit();
    this.ordersBindingSource.EndEdit();
    this.tableAdapterManager.UpdateAll(this.northwindDataSet);
    

Outre la validation des modifications sur une table enfant associée avant d’enregistrer des données dans une base de données, vous devrez peut-être également valider les enregistrements parents nouvellement créés avant d’ajouter de nouveaux enregistrements enfants à un jeu de données. En d’autres termes, vous devrez peut-être ajouter le nouvel enregistrement parent (Customer) au jeu de données avant que les contraintes de clé étrangère permettent d’ajouter de nouveaux enregistrements enfants (Orders) au jeu de données. Pour ce faire, vous pouvez utiliser l'événement BindingSource.AddingNew enfant.

Remarque

L’obligation de commiter les nouveaux enregistrements parents dépend du type de contrôle utilisé pour la liaison à votre source de données. Dans cette procédure pas à pas, vous utilisez des contrôles individuels pour la liaison à la table parente. Cela nécessite le code supplémentaire afin de valider le nouvel enregistrement parent. Si les enregistrements parents sont affichés à la place dans un contrôle de liaison complexe comme DataGridView, cet appel de EndEdit supplémentaire pour l’enregistrement parent n’est pas nécessaire. Cela est dû au fait que la fonctionnalité de liaison de données sous-jacente du contrôle gère la validation des nouveaux enregistrements.

Pour ajouter du code pour valider des enregistrements parents dans le jeu de données avant d’ajouter de nouveaux enregistrements enfants

  1. Créez un gestionnaire d’événements pour l’événement OrdersBindingSource.AddingNew .

    • Ouvrez Form1 en mode Création, sélectionnez OrdersBindingSource dans la barre d’état du composant, sélectionnez Événements dans la fenêtre Propriétés , puis double-cliquez sur l’événement AddNew .
  2. Ajoutez une ligne de code au gestionnaire d’événements qui appelle la CustomersBindingSource.EndEdit méthode. Le code du gestionnaire d’événements OrdersBindingSource_AddingNew doit ressembler à ce qui suit :

    this.customersBindingSource.EndEdit();
    

Référence TableAdapterManager

Par défaut, une TableAdapterManager classe est générée lorsque vous créez un jeu de données qui contient des tables associées. Pour empêcher la génération de la classe, remplacez la valeur de la Hierarchical Update propriété du jeu de données par false. Lorsque vous faites glisser une table qui a une relation sur l’aire de conception d’une page Windows Form ou WPF, Visual Studio déclare une variable membre de la classe. Si vous n’utilisez pas la liaison de données, vous devez déclarer manuellement la variable.

La TableAdapterManager classe n’est pas un type .NET. Par conséquent, vous ne pouvez pas le rechercher dans la documentation. Il est créé au moment du design dans le cadre du processus de création de jeu de données.

Voici les méthodes et propriétés fréquemment utilisées de la TableAdapterManager classe :

Membre Descriptif
méthode UpdateAll Enregistre toutes les données de toutes les tables de données.
Propriété BackUpDataSetBeforeUpdate Détermine s'il faut créer une copie de sauvegarde du jeu de données avant d'exécuter la méthode TableAdapterManager.UpdateAll. Booléen.
Propriété tableNameTableAdapter Représente un TableAdapter. Le généré TableAdapterManager contient une propriété pour chaque TableAdapter qu’elle gère. Par exemple, un jeu de données avec une table Customers and Orders est généré avec un TableAdapterManager qui contient CustomersTableAdapter et OrdersTableAdapter propriétés.
Propriété UpdateOrder Contrôle l’ordre des commandes d’insertion, de mise à jour et de suppression individuelles. Définissez cette valeur sur l’une des valeurs de l’énumération TableAdapterManager.UpdateOrderOption .

Par défaut, l’élément UpdateOrder est défini sur InsertUpdateDelete. Cela signifie que les insertions, les mises à jour, puis les suppressions sont effectuées pour toutes les tables du jeu de données.