Пакетное удаление (C#)Batch Deleting (C#)

по Скотт Митчеллby Scott Mitchell

Скачать код или скачать PDFDownload Code or Download PDF

Узнайте, как удалить несколько записей базы данных за одну операцию.Learn how to delete multiple database records in a single operation. На уровне пользовательского интерфейса мы создаем Улучшенный элемент управления GridView, созданный в предыдущем руководстве.In the User Interface Layer we build upon an enhanced GridView created in an earlier tutorial. На уровне доступа к данным мы переносите несколько операций удаления в рамках транзакции, чтобы гарантировать успешность всех удалений или отката всех удалений.In the Data Access Layer we wrap the multiple Delete operations within a transaction to ensure that all deletions succeed or all deletions are rolled back.

ВведениеIntroduction

В предыдущем учебнике было рассмотрено, как создать интерфейс редактирования пакетной службы с помощью полностью изменяемого GridView.The preceding tutorial explored how to create a batch editing interface using a fully-editable GridView. В ситуациях, когда пользователи часто редактируют много записей одновременно, интерфейсу редактирования пакетов потребуется гораздо меньше обратных передач и переключений контекста мыши, что повышает эффективность конечных пользователей.In situations where users are commonly editing many records at once, a batch editing interface will require far fewer postbacks and keyboard-to-mouse context switches, thereby improving the end user s efficiency. Этот метод также полезен для страниц, где пользователи часто удаляют много записей за один переход.This technique is similarly useful for pages where it is common for users to delete many records in one go.

Любой пользователь, который использовал Интернет-клиент электронной почты, уже знаком с одним из наиболее распространенных интерфейсов удаления пакетов: флажок в каждой строке сетки с соответствующей кнопкой Удалить все отмеченные элементы (см. рис. 1).Anyone who has used an online email client is already familiar with one of the most common batch deleting interfaces: a checkbox in each row in a grid with a corresponding Delete All Checked Items button (see Figure 1). Этот учебник довольно короткий, поскольку мы уже выполнили всю работу в предыдущих руководствах по созданию веб-интерфейса и метода удаления серии записей как единой атомарной операции.This tutorial is rather short because we ve already done all of the hard work in previous tutorials in creating both the web-based interface and a method to delete a series of records as a single atomic operation. В руководстве по добавлению в столбец GridView в учебнике "флажки" мы создали элемент управления GridView со столбцом флажков и в рамках руководства по транзакциям изменения базы данных , которые мы создали в BLL метод, который использовал транзакцию для удаления List<T> ProductID значений.In the Adding a GridView Column of Checkboxes tutorial we created a GridView with a column of checkboxes and in the Wrapping Database Modifications within a Transaction tutorial we created a method in the BLL that would use a transaction to delete a List<T> of ProductID values. В этом учебнике мы выполним сборку и слияние предыдущих возможностей, чтобы создать пример рабочего удаления пакета.In this tutorial, we will build upon and merge our previous experiences to create a working batch deleting example.

каждая строка содержит флажокEach Row Includes a Checkbox

Рис. 1. Каждая строка содержит флажок (щелкните, чтобы просмотреть изображение с полным размером)Figure 1: Each Row Includes a Checkbox (Click to view full-size image)

Шаг 1. Создание пакетного удаления интерфейсаStep 1: Creating the Batch Deleting Interface

Так как мы уже создали интерфейс удаления пакета в разделе Добавление столбца GridView в учебнике по флажкам, мы можем просто скопировать его в BatchDelete.aspx, а не создавать его с нуля.Since we already created the batch deleting interface in the Adding a GridView Column of Checkboxes tutorial, we can simply copy it to BatchDelete.aspx rather than creating it from scratch. Для начала откройте страницу BatchDelete.aspx в папке BatchData и странице CheckBoxField.aspx в папке EnhancedGridView.Start by opening the BatchDelete.aspx page in the BatchData folder and the CheckBoxField.aspx page in the EnhancedGridView folder. На странице CheckBoxField.aspx перейдите к представлению исходного кода и скопируйте разметку между тегами <asp:Content>, как показано на рис. 2.From the CheckBoxField.aspx page, go to the Source view and copy the markup between the <asp:Content> tags as shown in Figure 2.

скопировать декларативную разметку CheckBoxField. aspx в буфер обменаCopy the Declarative Markup of CheckBoxField.aspx to the Clipboard

Рис. 2. копирование декларативной разметки CheckBoxField.aspx в буфер обмена (щелкните, чтобы просмотреть изображение с полным размером)Figure 2: Copy the Declarative Markup of CheckBoxField.aspx to the Clipboard (Click to view full-size image)

Затем перейдите в представление исходного кода в BatchDelete.aspx и вставьте содержимое буфера обмена в теги <asp:Content>.Next, go to the Source view in BatchDelete.aspx and paste the contents of the clipboard within the <asp:Content> tags. Также скопируйте и вставьте код из класса кода программной части в CheckBoxField.aspx.cs в класс кода программной части в BatchDelete.aspx.cs (DeleteSelectedProducts Button s Click обработчик событий, метод ToggleCheckState и обработчики событий Click для кнопок CheckAll и UncheckAll).Also copy and paste the code from within the code-behind class in CheckBoxField.aspx.cs to within the code-behind class in BatchDelete.aspx.cs (the DeleteSelectedProducts Button s Click event handler, the ToggleCheckState method, and the Click event handlers for the CheckAll and UncheckAll Buttons). После копирования содержимого класс кода программной части BatchDelete.aspx страница s должен содержать следующий код:After copying over this content, the BatchDelete.aspx page s code-behind class should contain the following code:

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);
    }
}

После копирования декларативной разметки и исходного кода уделите несколько минут тестированию BatchDelete.aspx, просмотрев их в браузере.After copying over the declarative markup and source code, take a moment to test BatchDelete.aspx by viewing it through a browser. Вы увидите элемент управления GridView со списком первых десяти продуктов в GridView с каждой строкой, содержащей название продукта, категорию и цену вместе с флажком.You should see a GridView listing the first ten products in a GridView with each row listing the product s name, category, and price along with a checkbox. Должны быть три кнопки: проверить все, снять все и удалить выбранные продукты.There should be three buttons: Check All, Uncheck All, and Delete Selected Products. При нажатии кнопки "проверить все" выбираются все флажки, а снимите все флажки.Clicking the Check All button selects all checkboxes, while Uncheck All clears all checkboxes. При нажатии кнопки Удалить выбранные продукты отображается сообщение со списком ProductID значений выбранных продуктов, но на самом деле эти продукты не удаляются.Clicking Delete Selected Products displays a message that lists the ProductID values of the selected products, but does not actually delete the products.

интерфейс из CheckBoxField. aspx был перемещен в Батчделетинг. aspxThe Interface from CheckBoxField.aspx has been Moved to BatchDeleting.aspx

Рис. 3. интерфейс из CheckBoxField.aspx был перемещен в BatchDeleting.aspx (щелкните, чтобы просмотреть изображение с полным размером)Figure 3: The Interface from CheckBoxField.aspx has been Moved to BatchDeleting.aspx (Click to view full-size image)

Шаг 2. Удаление проверенных продуктов с помощью транзакцийStep 2: Deleting the Checked Products Using Transactions

Если пакет удаляется из пакета в BatchDeleting.aspx, остается только обновить код, чтобы кнопка Удалить выбранные продукты удалила проверенные продукты с помощью метода DeleteProductsWithTransaction в классе ProductsBLL.With the batch deleting interface successfully copied over to BatchDeleting.aspx, all that remains is to update the code so that the Delete Selected Products button deletes the checked products using the DeleteProductsWithTransaction method in the ProductsBLL class. Этот метод, добавленный в инструкции по переносу изменений базы данных в рамках руководства по транзакциям , принимает в качестве входных данных List<T> ProductID значений и удаляет все соответствующие ProductID в области транзакции.This method, added in the Wrapping Database Modifications within a Transaction tutorial, accepts as its input a List<T> of ProductID values and deletes each corresponding ProductID within the scope of a transaction.

DeleteSelectedProducts Button Click обработчик событий в настоящее время использует следующий цикл foreach для прохода по каждой строке GridView:The DeleteSelectedProducts Button s Click event handler currently uses the following foreach loop to iterate through each GridView row:

// 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);
        //............................................
    }
}

Для каждой строки ссылка на веб-элемент управления CheckBox ProductSelector программными средствами.For each row, the ProductSelector CheckBox Web control is programmatically referenced. Если флажок установлен, строка s ProductID извлекается из коллекции DataKeys и свойство DeleteResults метка s Text обновляется для включения сообщения, указывающего на то, что строка была выбрана для удаления.If it is checked, the row s ProductID is retrieved from the DataKeys collection and the DeleteResults Label s Text property is updated to include a message indicating that the row was selected for deletion.

Приведенный выше код фактически не удаляет какие-либо записи, так как вызов метода ProductsBLL класса s Delete комментария. Была ли эта логика удаления применена, код удалит продукты, но не в атомарной операции.The above code does not actually delete any records as the call to the ProductsBLL class s Delete method is commented out. Were this delete logic to be applied, the code would delete the products but not within an atomic operation. То есть, если первые несколько удалений в последовательности завершились с ошибкой позже (возможно, из-за нарушения ограничения внешнего ключа), будет создано исключение, но уже удаленные продукты останутся прежними.That is, if the first few deletes in the sequence succeeded, but a later one failed (perhaps due to a foreign key constraint violation), an exception would be thrown but those products already deleted would remain deleted.

Чтобы обеспечить атомарность, необходимо вместо этого использовать метод ProductsBLL Class s DeleteProductsWithTransaction.In order to assure atomicity, we need to instead use the ProductsBLL class s DeleteProductsWithTransaction method. Поскольку этот метод принимает список значений ProductID, необходимо сначала скомпилировать этот список из сетки, а затем передать его в качестве параметра.Because this method accepts a list of ProductID values, we need to first compile this list from the grid and then pass it as a parameter. Сначала мы создадим экземпляр List<T> типа int.We first create an instance of a List<T> of type int. В цикле foreach необходимо добавить выбранные продукты ProductID значения в эту List<T>.Within the foreach loop we need to add the selected products ProductID values to this List<T>. После цикла этот List<T> должен быть передан методу ProductsBLL класса s DeleteProductsWithTransaction.After the loop this List<T> must be passed to the ProductsBLL class s DeleteProductsWithTransaction method. Обновите DeleteSelectedProducts кнопку s Click обработчик событий, используя следующий код:Update the DeleteSelectedProducts Button s Click event handler with the following code:

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();
    }
}

Обновленный код создает List<T> типа int (productIDsToDelete) и заполняет его ProductIDными значениями для удаления.The updated code creates a List<T> of type int (productIDsToDelete) and populates it with the ProductID values to delete. Если после цикла foreachа выбран по крайней мере один продукт, вызывается метод ProductsBLL класса s DeleteProductsWithTransaction и этот список передается.After the foreach loop, if there is at least one product selected, the ProductsBLL class s DeleteProductsWithTransaction method is called and passed this list. Также отображается метка DeleteResults и данные, повторно привязанные к GridView (чтобы недавно удаленные записи больше не отображались в виде строк в сетке).The DeleteResults Label is also displayed and the data rebound to the GridView (so that the newly-deleted records no longer appear as rows in the grid).

На рис. 4 показан элемент управления GridView после выбора нескольких строк для удаления.Figure 4 shows the GridView after a number of rows have been selected for deletion. На рис. 5 показан экран сразу после нажатия кнопки Удалить выбранные продукты.Figure 5 shows the screen immediately after the Delete Selected Products button has been clicked. Обратите внимание, что на рис. 5 ProductID значения удаленных записей отображаются в метке под GridView, а эти строки больше не находятся в GridView.Note that in Figure 5 the ProductID values of the deleted records are displayed in the Label beneath the GridView and those rows are no longer in the GridView.

выбранные продукты будут удаленыThe Selected Products Will Be Deleted

Рис. 4. выбранные продукты будут удалены (щелкните, чтобы просмотреть изображение с полным размером)Figure 4: The Selected Products Will Be Deleted (Click to view full-size image)

значения ProductID для удаленных продуктов перечислены под GridViewThe Deleted Products ProductID Values are Listed Beneath the GridView

Рис. 5. удаленные продукты, ProductID значения перечислены под элементом управления GridView (щелкните, чтобы просмотреть изображение с полным размером)Figure 5: The Deleted Products ProductID Values are Listed Beneath the GridView (Click to view full-size image)

Note

Чтобы протестировать атомарность DeleteProductsWithTransaction метода, вручную добавьте запись для продукта в Order Details таблицу и попытайтесь удалить этот продукт (вместе с другими).To test the DeleteProductsWithTransaction method s atomicity, manually add an entry for a product in the Order Details table and then attempt to delete that product (along with others). При попытке удалить продукт с соответствующим порядком будет получено нарушение ограничения внешнего ключа, но обратите внимание, что выполняется откат других выбранных продуктов.You will receive a foreign key constraint violation when attempting to delete the product with an associated order, but note how the other selected products deletions are rolled back.

СводкаSummary

Создание пакетного удаления интерфейса включает добавление GridView со столбцом флажков и веб-элементом управления Button, который при нажатии удалит все выбранные строки как единую атомарную операцию.Creating a batch deleting interface involves adding a GridView with a column of checkboxes and a Button Web control that, when clicked, will delete all of the selected rows as a single atomic operation. В этом учебнике мы создали такой интерфейс, пиеЦинг совместную работу в двух предыдущих учебных курсах, добавив столбец GridView с флажками и заключив изменения базы данных в рамках транзакции.In this tutorial we built such an interface by piecing together work done in two previous tutorials, Adding a GridView Column of Checkboxes and Wrapping Database Modifications within a Transaction. В первом учебном курсе мы создали GridView со столбцом флажков, а в последнем мы реализовали в BLL метод, который при передаче List<T> из ProductIDных значений удаляет их все в области транзакции.In the first tutorial we created a GridView with a column of checkboxes and in the latter we implemented a method in the BLL that, when passed a List<T> of ProductID values, deleted them all within the scope of a transaction.

В следующем учебном курсе мы создадим интерфейс для выполнения пакетных вставок.In the next tutorial we'll create an interface for performing batch inserts.

Поздравляем с программированием!Happy Programming!

Об автореAbout the Author

Скотт Митчелл, автор семи книг по ASP/ASP. NET и основатель 4GuysFromRolla.com, работал с веб-технологиями Майкрософт с 1998.Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Скотт работает как независимый консультант, преподаватель и модуль записи.Scott works as an independent consultant, trainer, and writer. Его последняя книга — Sams обучать себя ASP.NET 2,0 за 24 часа.His latest book is Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Он доступен по адресу mitchell@4GuysFromRolla.com.He can be reached at mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.or via his blog, which can be found at http://ScottOnWriting.NET.

Специальная благодарностьSpecial Thanks To

Эта серия руководств была рассмотрена многими полезными рецензентами.This tutorial series was reviewed by many helpful reviewers. Потенциальные рецензенты для этого учебника были Хилтон Гизнау и Терезой Мерфи.Lead reviewers for this tutorial were Hilton Giesenow and Teresa Murphy. Хотите ознакомиться с моими будущими статьями MSDN?Interested in reviewing my upcoming MSDN articles? Если это так, расположите строку в mitchell@4GuysFromRolla.com.If so, drop me a line at mitchell@4GuysFromRolla.com.