Partager via


Gérer une exception de concurrence dans les applications de base de données .NET Framework

Remarque

Les jeux de données et les classes associées sont des technologies .NET Framework héritées qui datent du début des années 2000. Elles 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. Ces technologies sont particulièrement utiles aux applications qui permettent aux utilisateurs de modifier des données, et de rendre ces changements persistants dans la base de données. Même si les jeux de données sont une technologie très efficace, nous vous recommandons d’utiliser Entity Framework Core pour les nouvelles applications .NET. Entity Framework offre un moyen plus naturel d’utiliser des données tabulaires en tant que modèles objet. De plus, il présente une interface de programmation plus simple.

Les exceptions de concurrence (System.Data.DBConcurrencyException) sont levées lorsque deux utilisateurs tentent de modifier les mêmes données dans une base de données en même temps. Dans cette procédure pas à pas, vous créez une application Windows qui montre comment intercepter un DBConcurrencyException, localiser la ligne à l’origine de l’erreur et découvrir une stratégie pour la gérer.

Cette procédure pas à pas vous guide tout au long des étapes suivantes :

  1. Créez un nouveau projet Application Windows Forms (.NET Framework).

  2. Créez un jeu de données basé sur la table Clients Northwind.

  3. Créez un formulaire avec un DataGridView pour afficher les données.

  4. Remplissez un jeu de données avec les données de la table Clients dans la base de données Northwind.

  5. Utilisez la fonctionnalité Afficher les données de table dans l’Explorateur de serveurs pour accéder aux données de la table Clients et modifier un enregistrement.

  6. Modifiez le même enregistrement en une autre valeur, mettez à jour le jeu de données et tentez d’écrire les modifications apportées à la base de données, ce qui entraîne la levée d’une erreur d’accès concurrentiel.

  7. Interceptez l’erreur, puis affichez les différentes versions de l’enregistrement, ce qui permet à l’utilisateur de déterminer s’il faut continuer et mettre à jour la base de données, ou annuler la mise à jour.

Prérequis

Ce guide pas à pas utilise SQL Server Express LocalDB et l’échantillon de base de données Northwind.

  1. Si SQL Server Express LocalDB n’est pas installé, installez-le à partir de la page de téléchargement SQL Server Express, ou via le programme d’installation Visual Studio Installer. Dans Visual Studio Installer, vous pouvez installer la base de données locale SQL Server Express dans le cadre de la charge de travail Traitement et stockage de données, ou l’installer comme un composant seul.

  2. Installez l’exemple de base de données Northwind en procédant comme suit :

    1. Dans Visual Studio, ouvrez la fenêtre de l’Explorateur d’objets SQL Server. (L’Explorateur d’objets SQL Server est installé dans le cadre de la charge de travail stockage de données et du traitement dans Visual Studio Installer.) Développez le nœud SQL Server. Cliquez avec le bouton droit sur votre instance LocalDB et sélectionnez Nouvelle requête.

      Une fenêtre d’éditeur de requête s’ouvre.

    2. Copiez le script Northwind Transact-SQL dans votre Presse-papiers. Ce script T-SQL crée la base de données Northwind à partir de zéro et la remplit avec des données.

    3. Collez le script T-SQL dans l’éditeur de requête, puis cliquez sur le bouton Exécuter.

      Après un court laps de temps, la requête se termine et la base de données Northwind est créée.

Création d'un projet

Commencez par créer une nouvelle application Windows Forms.

  1. Dans Visual Studio, dans le menu Fichier, sélectionnez Nouveau>Projet.

  2. Développez Visual C# ou Visual Basic dans le volet gauche, puis sélectionnez Windows Desktop.

  3. Dans le volet central, sélectionnez le type de projet d’application Windows Forms.

  4. Nommez le projet ConcurrencyWalkthrough, puis choisissez OK.

    Le projet ConcurrencyWalkthrough est créé et ajouté à Explorateur de solutions, et un nouveau formulaire s’ouvre dans le concepteur.

Créer le jeu de données Northwind

Ensuite, créez un jeu de données nommé NorthwindDataSet :

  1. Dans le menu Données, choisissez Ajouter une nouvelle source de données.

    L’Assistant Configuration de source de données s’ouvre.

  2. Sur l’écran Choisir un type de source de données, sélectionnez Base de données.

    Assistant de configuration de source de données dans Visual Studio

  3. Sélectionnez une connexion à l’échantillon de base de données Northwind dans la liste des connexions disponibles. Si la connexion n’est pas disponible dans la liste des connexions, sélectionnez Nouvelle connexion.

    Notes

    Si vous vous connectez à un fichier de base de données local, sélectionnez Non lorsque vous êtes invité à ajouter le fichier à votre projet.

  4. Dans l’écran Enregistrer la chaîne de connexion dans le fichier Configuration de l’application, sélectionnez Suivant.

  5. Développez le nœud Table et sélectionnez la table Clients . Le nom par défaut du jeu de données doit être NorthwindDataSet.

  6. Sélectionnez Terminer pour ajouter l’événement au projet.

Créer un contrôle DataGridView lié aux données

Dans cette section, vous créez un System.Windows.Forms.DataGridView en faisant glisser l’élément Clients de la fenêtre Sources de données vers votre Windows Form.

  1. Pour ouvrir la fenêtre Sources de données, dans le menu Données, cliquez sur Afficher les sources de données.

  2. Dans la fenêtre Sources de données, développez le nœud NorthwindDataSet, puis sélectionnez la table Clients.

  3. Sélectionnez la flèche vers le bas sur le nœud de table, puis sélectionnez DataGridView dans la liste déroulante.

  4. Faites glisser la table sur une zone vide de votre formulaire.

    Un DataGridView contrôle nommé CustomersDataGridView et un BindingNavigator nommé CustomersBindingNavigator sont ajoutés au formulaire lié à BindingSource. Celui-ci est à son tour lié à la table Clients dans northwindDataSet.

Tester le formulaire

Vous pouvez maintenant tester le formulaire pour vous assurer qu’il se comporte comme prévu jusqu’à ce stade :

  1. Sélectionnez F5 pour exécuter l'application.

    Le formulaire s’affiche avec un contrôle DataGridView rempli de données de table Clients.

  2. Dans le menu Déboguer, sélectionnez Arrêter le débogage.

Gérer les erreurs d’accès concurrentiel

La façon dont vous gérez les erreurs dépend des règles métier spécifiques qui régissent votre application. Pour cette procédure pas à pas, nous utilisons la stratégie suivante comme exemple de gestion de l’erreur d’accès concurrentiel.

L’application présente à l’utilisateur trois versions de l’enregistrement :

  • Enregistrement actif dans la base de données

  • Enregistrement d’origine chargé dans le jeu de données

  • Modifications proposées dans le jeu de données

L’utilisateur peut alors remplacer la base de données avec la version proposée ou annuler la mise à jour et actualiser le jeu de données avec les nouvelles valeurs de la base de données.

Pour activer la gestion des erreurs d’accès concurrentiel

  1. Créez un gestionnaire d’erreurs personnalisé.

  2. Affichez les choix à l’utilisateur.

  3. Traitez la réponse de l’utilisateur.

  4. Renvoyez la mise à jour ou réinitialisez les données dans le jeu de données.

Ajouter du code pour gérer l’exception d’accès concurrentiel

Lorsque vous tentez d’effectuer une mise à jour et qu’une exception est levée, il convient généralement de faire quelque chose avec les informations fournies par l’exception levée. Dans cette section, vous ajoutez du code qui tente de mettre à jour la base de données. Vous gérez également tous les DBConcurrencyException susceptibles d’être déclenchés, ainsi que toutes les autres exceptions.

Notes

Les méthodes CreateMessage et ProcessDialogResults sont ajoutées plus loin dans la procédure pas à pas.

  1. Ajoutez le code suivant à la méthode Form1_Load :

    private void UpdateDatabase()
    {
        try
        {
            this.customersTableAdapter.Update(this.northwindDataSet.Customers);
            MessageBox.Show("Update successful");
        }
        catch (DBConcurrencyException dbcx)
        {
            DialogResult response = MessageBox.Show(CreateMessage((NorthwindDataSet.CustomersRow)
                (dbcx.Row)), "Concurrency Exception", MessageBoxButtons.YesNo);
    
            ProcessDialogResult(response);
        }
        catch (Exception ex)
        {
            MessageBox.Show("An error was thrown while attempting to update the database.");
        }
    }
    

  1. Remplacez la méthode CustomersBindingNavigatorSaveItem_Click pour appeler la méthode UpdateDatabase afin qu’elle ressemble à ce qui suit :

    private void customersBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        UpdateDatabase();
    }
    

Afficher les choix à l’utilisateur

Le code que vous venez d’écrire appelle la procédure CreateMessage pour afficher les informations d’erreur à l’utilisateur. Pour cette procédure pas à pas, vous utilisez une zone de message pour afficher les différentes versions de l’enregistrement à l’utilisateur. Cela permet à l’utilisateur de choisir de remplacer l’enregistrement avec les modifications ou d’annuler la modification. Une fois que l’utilisateur sélectionne une option (clique sur un bouton) dans la zone de message, la réponse est passée à la méthode ProcessDialogResult.

Créez le message en ajoutant le code suivant à l’éditeur de code. Entrez ce code sous la méthode UpdateDatabase :

private string CreateMessage(NorthwindDataSet.CustomersRow cr)
{
    return
        "Database: " + GetRowData(GetCurrentRowInDB(cr), DataRowVersion.Default) + "\n" +
        "Original: " + GetRowData(cr, DataRowVersion.Original) + "\n" +
        "Proposed: " + GetRowData(cr, DataRowVersion.Current) + "\n" +
        "Do you still want to update the database with the proposed value?";
}


//--------------------------------------------------------------------------
// This method loads a temporary table with current records from the database
// and returns the current values from the row that caused the exception.
//--------------------------------------------------------------------------
private NorthwindDataSet.CustomersDataTable tempCustomersDataTable = 
    new NorthwindDataSet.CustomersDataTable();

private NorthwindDataSet.CustomersRow GetCurrentRowInDB(NorthwindDataSet.CustomersRow RowWithError)
{
    this.customersTableAdapter.Fill(tempCustomersDataTable);

    NorthwindDataSet.CustomersRow currentRowInDb = 
        tempCustomersDataTable.FindByCustomerID(RowWithError.CustomerID);

    return currentRowInDb;
}


//--------------------------------------------------------------------------
// This method takes a CustomersRow and RowVersion 
// and returns a string of column values to display to the user.
//--------------------------------------------------------------------------
private string GetRowData(NorthwindDataSet.CustomersRow custRow, DataRowVersion RowVersion)
{
    string rowData = "";

    for (int i = 0; i < custRow.ItemArray.Length ; i++ )
    {
        rowData = rowData + custRow[i, RowVersion].ToString() + " ";
    }
    return rowData;
}

Traiter la réponse de l’utilisateur

Vous avez également besoin de code pour traiter la réponse de l’utilisateur à la zone de message. Les options sont soit de remplacer l’enregistrement actif dans la base de données avec la modification proposée, soit d’abandonner les modifications locales et d’actualiser la table de données avec l’enregistrement qui se trouve actuellement dans la base de données. Si l’utilisateur choisit Oui, la méthode Merge est appelée avec l’argument preserveChanges défini sur true. Cela entraîne la réussite de la tentative de mise à jour, car la version d’origine de l’enregistrement correspond désormais à l’enregistrement dans la base de données.

Ajoutez le code suivant sous le code qui a été ajouté dans la section précédente :

// This method takes the DialogResult selected by the user and updates the database 
// with the new values or cancels the update and resets the Customers table 
// (in the dataset) with the values currently in the database.

private void ProcessDialogResult(DialogResult response)
{
    switch (response)
    {
        case DialogResult.Yes:
            northwindDataSet.Merge(tempCustomersDataTable, true, MissingSchemaAction.Ignore);
            UpdateDatabase();
            break;

        case DialogResult.No:
            northwindDataSet.Merge(tempCustomersDataTable);
            MessageBox.Show("Update cancelled");
            break;
    }
}

Tester le comportement du formulaire

Vous pouvez maintenant tester le formulaire pour vous assurer qu’il se comporte comme prévu. Pour simuler une violation d’accès concurrentiel, vous modifiez les données de la base de données après avoir rempli le NorthwindDataSet.

  1. Sélectionnez F5 pour exécuter l'application.

  2. Une fois le formulaire affiché, laissez-le en cours d’exécution et basculez vers l’IDE Visual Studio.

  3. Dans le menu Affichage, cliquez sur Explorateur de serveurs.

  4. Dans l’Explorateur de serveurs, développez la connexion utilisée par votre application, puis développez le nœud Tables .

  5. Cliquez avec le bouton droit sur la table Clients, puis sélectionnez Afficher les données de table.

  6. Dans le premier enregistrement (ALFKI), remplacez ContactName par Maria Anders2.

    Notes

    Accédez à une autre ligne pour valider la modification.

  7. Basculez vers le formulaire en cours d’exécution de ConcurrencyWalkthrough.

  8. Dans le premier enregistrement sur le formulaire (ALFKI), remplacez ContactName par Maria Anders1.

  9. Sélectionnez le bouton Enregistrer.

    L’erreur d’accès concurrentiel est déclenchée et la zone de message s’affiche.

    Sélectionner Non annule la mise à jour et met à jour le jeu de données avec les valeurs qui se trouvent actuellement dans la base de données. Sélectionner Oui écrit la valeur proposée dans la base de données.