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

по Скотт Митчелл

Скачать код или скачать PDF

Узнайте, как удалить несколько записей базы данных за одну операцию. На уровне пользовательского интерфейса мы создаем Улучшенный элемент управления GridView, созданный в предыдущем руководстве. На уровне доступа к данным мы переносите несколько операций удаления в рамках транзакции, чтобы гарантировать успешность всех удалений или отката всех удалений.

Введение

В предыдущем учебнике было рассмотрено, как создать интерфейс редактирования пакетной службы с помощью полностью изменяемого GridView. В ситуациях, когда пользователи часто редактируют много записей одновременно, интерфейсу редактирования пакетов потребуется гораздо меньше обратных передач и переключений контекста мыши, что повышает эффективность конечных пользователей. Этот метод также полезен для страниц, где пользователи часто удаляют много записей за один переход.

Любой пользователь, который использовал Интернет-клиент электронной почты, уже знаком с одним из наиболее распространенных интерфейсов удаления пакетов: флажок в каждой строке сетки с соответствующей кнопкой Удалить все отмеченные элементы (см. рис. 1). Этот учебник довольно короткий, поскольку мы уже выполнили всю работу в предыдущих руководствах по созданию веб-интерфейса и метода удаления серии записей как единой атомарной операции. В руководстве по добавлению в столбец GridView в учебнике "флажки" мы создали элемент управления GridView со столбцом флажков и в рамках руководства по транзакциям изменения базы данных , которые мы создали в BLL метод, который использовал транзакцию для удаления List<T> ProductID значений. В этом учебнике мы выполним сборку и слияние предыдущих возможностей, чтобы создать пример рабочего удаления пакета.

каждая строка содержит флажок

Рис. 1. Каждая строка содержит флажок (щелкните, чтобы просмотреть изображение с полным размером)

Шаг 1. Создание пакетного удаления интерфейса

Так как мы уже создали интерфейс удаления пакета в разделе Добавление столбца GridView в учебнике по флажкам, мы можем просто скопировать его в BatchDelete.aspx, а не создавать его с нуля. Для начала откройте страницу BatchDelete.aspx в папке BatchData и странице CheckBoxField.aspx в папке EnhancedGridView. На странице CheckBoxField.aspx перейдите к представлению исходного кода и скопируйте разметку между тегами <asp:Content>, как показано на рис. 2.

скопировать декларативную разметку CheckBoxField. aspx в буфер обмена

Рис. 2. копирование декларативной разметки CheckBoxField.aspx в буфер обмена (щелкните, чтобы просмотреть изображение с полным размером)

Затем перейдите в представление исходного кода в BatchDelete.aspx и вставьте содержимое буфера обмена в теги <asp:Content>. Также скопируйте и вставьте код из класса кода программной части в CheckBoxField.aspx.cs в класс кода программной части в BatchDelete.aspx.cs (DeleteSelectedProducts Button s Click обработчик событий, метод ToggleCheckState и обработчики событий Click для кнопок CheckAll и UncheckAll). После копирования содержимого класс кода программной части BatchDelete.aspx страница s должен содержать следующий код:

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, просмотрев их в браузере. Вы увидите элемент управления GridView со списком первых десяти продуктов в GridView с каждой строкой, содержащей название продукта, категорию и цену вместе с флажком. Должны быть три кнопки: проверить все, снять все и удалить выбранные продукты. При нажатии кнопки "проверить все" выбираются все флажки, а снимите все флажки. При нажатии кнопки Удалить выбранные продукты отображается сообщение со списком ProductID значений выбранных продуктов, но на самом деле эти продукты не удаляются.

интерфейс из CheckBoxField. aspx был перемещен в Батчделетинг. aspx

Рис. 3. интерфейс из CheckBoxField.aspx был перемещен в BatchDeleting.aspx (щелкните, чтобы просмотреть изображение с полным размером)

Шаг 2. Удаление проверенных продуктов с помощью транзакций

Если пакет удаляется из пакета в BatchDeleting.aspx, остается только обновить код, чтобы кнопка Удалить выбранные продукты удалила проверенные продукты с помощью метода DeleteProductsWithTransaction в классе ProductsBLL. Этот метод, добавленный в инструкции по переносу изменений базы данных в рамках руководства по транзакциям , принимает в качестве входных данных List<T> ProductID значений и удаляет все соответствующие ProductID в области транзакции.

DeleteSelectedProducts Button Click обработчик событий в настоящее время использует следующий цикл foreach для прохода по каждой строке 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);
        //............................................
    }
}

Для каждой строки ссылка на веб-элемент управления CheckBox ProductSelector программными средствами. Если флажок установлен, строка s ProductID извлекается из коллекции DataKeys и свойство DeleteResults метка s Text обновляется для включения сообщения, указывающего на то, что строка была выбрана для удаления.

Приведенный выше код фактически не удаляет какие-либо записи, так как вызов метода ProductsBLL класса s Delete комментария. Была ли эта логика удаления применена, код удалит продукты, но не в атомарной операции. То есть, если первые несколько удалений в последовательности завершились с ошибкой позже (возможно, из-за нарушения ограничения внешнего ключа), будет создано исключение, но уже удаленные продукты останутся прежними.

Чтобы обеспечить атомарность, необходимо вместо этого использовать метод ProductsBLL Class s DeleteProductsWithTransaction. Поскольку этот метод принимает список значений ProductID, необходимо сначала скомпилировать этот список из сетки, а затем передать его в качестве параметра. Сначала мы создадим экземпляр List<T> типа int. В цикле foreach необходимо добавить выбранные продукты ProductID значения в эту List<T>. После цикла этот List<T> должен быть передан методу ProductsBLL класса s DeleteProductsWithTransaction. Обновите DeleteSelectedProducts кнопку s Click обработчик событий, используя следующий код:

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ными значениями для удаления. Если после цикла foreachа выбран по крайней мере один продукт, вызывается метод ProductsBLL класса s DeleteProductsWithTransaction и этот список передается. Также отображается метка DeleteResults и данные, повторно привязанные к GridView (чтобы недавно удаленные записи больше не отображались в виде строк в сетке).

На рис. 4 показан элемент управления GridView после выбора нескольких строк для удаления. На рис. 5 показан экран сразу после нажатия кнопки Удалить выбранные продукты. Обратите внимание, что на рис. 5 ProductID значения удаленных записей отображаются в метке под GridView, а эти строки больше не находятся в GridView.

выбранные продукты будут удалены

Рис. 4. выбранные продукты будут удалены (щелкните, чтобы просмотреть изображение с полным размером)

значения ProductID для удаленных продуктов перечислены под GridView

Рис. 5. удаленные продукты, ProductID значения перечислены под элементом управления GridView (щелкните, чтобы просмотреть изображение с полным размером)

Note

Чтобы протестировать атомарность DeleteProductsWithTransaction метода, вручную добавьте запись для продукта в Order Details таблицу и попытайтесь удалить этот продукт (вместе с другими). При попытке удалить продукт с соответствующим порядком будет получено нарушение ограничения внешнего ключа, но обратите внимание, что выполняется откат других выбранных продуктов.

Сводка

Создание пакетного удаления интерфейса включает добавление GridView со столбцом флажков и веб-элементом управления Button, который при нажатии удалит все выбранные строки как единую атомарную операцию. В этом учебнике мы создали такой интерфейс, пиеЦинг совместную работу в двух предыдущих учебных курсах, добавив столбец GridView с флажками и заключив изменения базы данных в рамках транзакции. В первом учебном курсе мы создали GridView со столбцом флажков, а в последнем мы реализовали в BLL метод, который при передаче List<T> из ProductIDных значений удаляет их все в области транзакции.

В следующем учебном курсе мы создадим интерфейс для выполнения пакетных вставок.

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

Об авторе

Скотт Митчелл, автор семи книг по ASP/ASP. NET и основатель 4GuysFromRolla.com, работал с веб-технологиями Майкрософт с 1998. Скотт работает как независимый консультант, преподаватель и модуль записи. Его последняя книга — Sams обучать себя ASP.NET 2,0 за 24 часа. Он доступен по адресу mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.

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

Эта серия руководств была рассмотрена многими полезными рецензентами. Потенциальные рецензенты для этого учебника были Хилтон Гизнау и Терезой Мерфи. Хотите ознакомиться с моими будущими статьями MSDN? Если это так, расположите строку в mitchell@4GuysFromRolla.com.