Partager via


Suppression par lots (C#)

par Scott Mitchell

Télécharger le PDF

Découvrez comment supprimer plusieurs enregistrements de base de données en une seule opération. Dans la couche d’interface utilisateur, nous nous appuyons sur un GridView amélioré créé dans un tutoriel précédent. Dans la couche d’accès aux données, nous encapsulons les plusieurs opérations de suppression au sein d’une transaction pour nous assurer que toutes les suppressions réussissent ou que toutes les suppressions sont restaurées.

Introduction

Le tutoriel précédent a exploré comment créer une interface d’édition par lots à l’aide d’un GridView entièrement modifiable. Dans les situations où les utilisateurs modifient généralement de nombreux enregistrements à la fois, une interface d’édition par lots nécessite beaucoup moins de publications et de commutateurs de contexte de clavier à souris, ce qui améliore l’efficacité de l’utilisateur final. Cette technique est également utile pour les pages où il est courant pour les utilisateurs de supprimer de nombreux enregistrements en une seule fois.

Toute personne ayant utilisé un client de messagerie en ligne est déjà familiarisée avec l’une des interfaces de suppression par lots les plus courantes : une case à cocher dans chaque ligne d’une grille avec un bouton Supprimer tous les éléments vérifiés correspondant (voir figure 1). Ce tutoriel est assez court, car nous avons déjà effectué tout le travail acharné des tutoriels précédents en créant à la fois l’interface web et une méthode pour supprimer une série d’enregistrements en tant qu’opération atomique unique. Dans le didacticiel Ajout d’une colonne GridView de cases à cocher , nous avons créé un GridView avec une colonne de cases à cocher et, dans le didacticiel Wrapping Database Modifications dans un transaction , nous avons créé une méthode dans le BLL qui utiliserait une transaction pour supprimer un List<T> de ProductID valeurs. Dans ce tutoriel, nous allons nous appuyer sur nos expériences précédentes et les fusionner pour créer un exemple de suppression par lots de travail.

Chaque ligne inclut une case à cocher

Figure 1 : Chaque ligne inclut une case à cocher (cliquer pour afficher l’image en taille réelle)

Étape 1 : Création de l’interface de suppression de lot

Étant donné que nous avons déjà créé l’interface de suppression par lots dans le didacticiel Ajout d’une colonne GridView de cases à cocher , nous pouvons simplement la copier vers plutôt que de la créer à BatchDelete.aspx partir de zéro. Commencez par ouvrir la BatchDelete.aspx page dans le BatchData dossier et la CheckBoxField.aspx page dans le EnhancedGridView dossier. Dans la CheckBoxField.aspx page, accédez à la vue Source et copiez le balisage entre les balises, comme illustré dans la <asp:Content> figure 2.

Copier le balisage déclaratif de CheckBoxField.aspx dans le Presse-papiers

Figure 2 : Copier le balisage déclaratif de CheckBoxField.aspx dans le Presse-papiers (cliquer pour afficher l’image en taille réelle)

Ensuite, accédez à la vue Source dans BatchDelete.aspx et collez le contenu du Presse-papiers dans les <asp:Content> balises. Copiez et collez également le code à partir de la classe code-behind dans CheckBoxField.aspx.cs vers dans la classe code-behind dans BatchDelete.aspx.cs (le DeleteSelectedProducts gestionnaire d’événements Click Button, la ToggleCheckState méthode et les Click gestionnaires d’événements pour les CheckAll boutons et UncheckAll ). Après avoir copié ce contenu, la classe code-behind de la BatchDelete.aspx page doit contenir le code suivant :

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class BatchData_BatchDelete : System.Web.UI.Page
{
    protected void DeleteSelectedProducts_Click(object sender, EventArgs e)
    {
        bool atLeastOneRowDeleted = false;
        // Iterate through the Products.Rows property
        foreach (GridViewRow row in Products.Rows)
        {
            // Access the CheckBox
            CheckBox cb = (CheckBox)row.FindControl("ProductSelector");
            if (cb != null && cb.Checked)
            {
                // Delete row! (Well, not really...)
                atLeastOneRowDeleted = true;
                // First, get the ProductID for the selected row
                int productID = Convert.ToInt32(Products.DataKeys[row.RowIndex].Value);
                // "Delete" the row
                DeleteResults.Text += string.Format
                    ("This would have deleted ProductID {0}<br />", productID);
                //... To actually delete the product, use ...
                //ProductsBLL productAPI = new ProductsBLL();
                //productAPI.DeleteProduct(productID);
                //............................................
            }
        }
        // Show the Label if at least one row was deleted...
        DeleteResults.Visible = atLeastOneRowDeleted;
    }
    private void ToggleCheckState(bool checkState)
    {
        // Iterate through the Products.Rows property
        foreach (GridViewRow row in Products.Rows)
        {
            // Access the CheckBox
            CheckBox cb = (CheckBox)row.FindControl("ProductSelector");
            if (cb != null)
                cb.Checked = checkState;
        }
    }
    protected void CheckAll_Click(object sender, EventArgs e)
    {
        ToggleCheckState(true);
    }
    protected void UncheckAll_Click(object sender, EventArgs e)
    {
        ToggleCheckState(false);
    }
}

Après avoir copié le balisage déclaratif et le code source, prenez un moment pour le tester BatchDelete.aspx en l’affichant via un navigateur. Vous devriez voir un GridView répertoriant les dix premiers produits dans un GridView avec chaque ligne indiquant le nom, la catégorie et le prix du produit, ainsi qu’une case à cocher. Il doit y avoir trois boutons : Vérifier tout, Désactiver tout et Supprimer les produits sélectionnés. Le fait de cliquer sur le bouton Vérifier tout permet de cocher toutes les cases à cocher, tandis que La case Désactiver tout désactive toutes les cases. Cliquer sur Supprimer les produits sélectionnés affiche un message qui répertorie les ProductID valeurs des produits sélectionnés, mais ne supprime pas réellement les produits.

L’interface de CheckBoxField.aspx a été déplacée vers BatchDeleting.aspx

Figure 3 : L’interface de CheckBoxField.aspx a été déplacée vers BatchDeleting.aspx (Cliquer pour afficher l’image en taille réelle)

Étape 2 : Suppression des produits vérifiés à l’aide de transactions

Une fois l’interface de suppression par lots correctement copiée dans BatchDeleting.aspx, il ne reste plus qu’à mettre à jour le code afin que le bouton Supprimer les produits sélectionnés supprime les produits vérifiés à l’aide de la DeleteProductsWithTransaction méthode dans la ProductsBLL classe . Cette méthode, ajoutée dans le didacticiel Wrapping Database Modifications dans un didacticiel Transaction , accepte comme entrée a List<T> de ProductID valeurs et supprime chacune correspondant ProductID dans l’étendue d’une transaction.

Le DeleteSelectedProducts gestionnaire d’événements Button Click utilise actuellement la boucle suivante foreach pour itérer sur chaque ligne GridView :

// Iterate through the Products.Rows property
foreach (GridViewRow row in Products.Rows)
{
    // Access the CheckBox
    CheckBox cb = (CheckBox)row.FindControl("ProductSelector");
    if (cb != null && cb.Checked)
    {
        // Delete row! (Well, not really...)
        atLeastOneRowDeleted = true;
        // First, get the ProductID for the selected row
        int productID = Convert.ToInt32(Products.DataKeys[row.RowIndex].Value);
        // "Delete" the row
        DeleteResults.Text += string.Format
            ("This would have deleted ProductID {0}<br />", productID);
        //... To actually delete the product, use ...
        //ProductsBLL productAPI = new ProductsBLL();
        //productAPI.DeleteProduct(productID);
        //............................................
    }
}

Pour chaque ligne, le ProductSelector contrôle Web CheckBox est référencé par programmation. Si elle est cochée, la ligne s ProductID est récupérée à partir de la DataKeys collection et la DeleteResults propriété Label s Text est mise à jour pour inclure un message indiquant que la ligne a été sélectionnée pour suppression.

Le code ci-dessus ne supprime pas réellement d’enregistrements, car l’appel à la méthode s de classe ProductsBLL est Delete commenté. Si cette logique de suppression devait être appliquée, le code supprimerait les produits, mais pas dans une opération atomique. Autrement dit, si les premières suppressions de la séquence ont réussi, mais qu’une autre a échoué (peut-être en raison d’une violation de contrainte de clé étrangère), une exception serait levée, mais ces produits déjà supprimés resteraient supprimés.

Pour garantir l’atomicité, nous devons plutôt utiliser la méthode de classe ProductsBLL s DeleteProductsWithTransaction . Étant donné que cette méthode accepte une liste de ProductID valeurs, nous devons d’abord compiler cette liste à partir de la grille, puis la transmettre en tant que paramètre. Nous créons d’abord un instance d’un List<T> de type int. Dans la foreach boucle, nous devons ajouter les valeurs de produits ProductID sélectionnées à ce List<T>. Après la boucle, cela List<T> doit être passé à la ProductsBLL méthode class s DeleteProductsWithTransaction . Mettez à jour le DeleteSelectedProducts gestionnaire d’événements Button Click avec le code suivant :

protected void DeleteSelectedProducts_Click(object sender, EventArgs e)
{
    // Create a List to hold the ProductID values to delete
    System.Collections.Generic.List<int> productIDsToDelete = 
        new System.Collections.Generic.List<int>();
    // Iterate through the Products.Rows property
    foreach (GridViewRow row in Products.Rows)
    {
        // Access the CheckBox
        CheckBox cb = (CheckBox)row.FindControl("ProductSelector");
        if (cb != null && cb.Checked)
        {
            // Save the ProductID value for deletion
            // First, get the ProductID for the selected row
            int productID = Convert.ToInt32(Products.DataKeys[row.RowIndex].Value);
            // Add it to the List...
            productIDsToDelete.Add(productID);
            // Add a confirmation message
            DeleteResults.Text += string.Format
                ("ProductID {0} has been deleted<br />", productID);
        }
    }
    // Call the DeleteProductsWithTransaction method and show the Label 
    // if at least one row was deleted...
    if (productIDsToDelete.Count > 0)
    {
        ProductsBLL productAPI = new ProductsBLL();
        productAPI.DeleteProductsWithTransaction(productIDsToDelete);
        DeleteResults.Visible = true;
        // Rebind the data to the GridView
        Products.DataBind();
    }
}

Le code mis à jour crée un List<T> de type int (productIDsToDelete) et le remplit avec les ProductID valeurs à supprimer. Après la foreach boucle, si au moins un produit est sélectionné, la ProductsBLL méthode class s DeleteProductsWithTransaction est appelée et a passé cette liste. L’étiquette DeleteResults est également affichée et les données rebondissent vers GridView (de sorte que les enregistrements récemment supprimés n’apparaissent plus sous forme de lignes dans la grille).

La figure 4 montre gridView une fois qu’un certain nombre de lignes ont été sélectionnées pour suppression. La figure 5 montre l’écran immédiatement après que vous avez cliqué sur le bouton Supprimer les produits sélectionnés. Notez que dans la figure 5, les ProductID valeurs des enregistrements supprimés sont affichées dans l’étiquette sous GridView et que ces lignes ne se trouvent plus dans gridView.

Les produits sélectionnés seront supprimés

Figure 4 : Les produits sélectionnés seront supprimés (cliquez pour afficher l’image en taille réelle)

Les valeurs ProductID des produits supprimés sont répertoriées sous gridView

Figure 5 : Les valeurs des produits ProductID supprimés sont répertoriées sous gridView (cliquer pour afficher l’image en taille réelle)

Notes

Pour tester l’atomicité de la DeleteProductsWithTransaction méthode, ajoutez manuellement une entrée pour un produit dans la Order Details table, puis tentez de supprimer ce produit (avec d’autres). Vous recevrez une violation de contrainte de clé étrangère lorsque vous tentez de supprimer le produit avec une commande associée, mais notez comment les autres suppressions de produits sélectionnés sont annulées.

Résumé

La création d’une interface de suppression par lots implique l’ajout d’un GridView avec une colonne de cases à cocher et d’un contrôle Web Button qui, en cas de clic, supprime toutes les lignes sélectionnées en tant qu’opération atomique unique. Dans ce tutoriel, nous avons créé une telle interface en regroupant le travail effectué dans deux didacticiels précédents, ajout d’une colonne GridView de cases à cocher et habillage des modifications de base de données dans une transaction. Dans le premier tutoriel, nous avons créé un GridView avec une colonne de cases à cocher et dans ce dernier, nous avons implémenté une méthode dans le BLL qui, lors de la transmission d’un List<T> de ProductID valeurs, les a supprimées toutes dans l’étendue d’une transaction.

Dans le tutoriel suivant, nous allons créer une interface pour effectuer des insertions par lots.

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 comme consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 2.0 in 24 Heures. Il est accessible à l’adressemitchell@4GuysFromRolla.com . ou via son blog, qui peut être trouvé à l’adresse http://ScottOnWriting.NET.

Un merci spécial à

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