Поделиться через


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

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

Скачивание 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.vb в класс программной части внутри BatchDelete.aspx.vb (обработчик событий DeleteSelectedProducts Button Click, метод ToggleCheckState, и обработчики событий для кнопок Click и CheckAll). После копирования этого содержимого на страницу класс кода, находящийся за страницей BatchDelete.aspx, должен содержать следующий код:

Partial Class BatchData_BatchDelete
    Inherits System.Web.UI.Page
    Protected Sub DeleteSelectedProducts_Click(sender As Object, e As EventArgs) _
        Handles DeleteSelectedProducts.Click
        
        Dim atLeastOneRowDeleted As Boolean = False
        ' Iterate through the Products.Rows property
        For Each row As GridViewRow In Products.Rows
            ' Access the CheckBox
            Dim cb As CheckBox = row.FindControl("ProductSelector")
            If cb IsNot Nothing AndAlso cb.Checked Then
                ' Delete row! (Well, not really...)
                atLeastOneRowDeleted = True
                ' First, get the ProductID for the selected row
                Dim productID As Integer = _
                    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 ...
                ' Dim productAPI As New ProductsBLL
                ' productAPI.DeleteProduct(productID)
                '............................................
            End If
        Next
        ' Show the Label if at least one row was deleted...
        DeleteResults.Visible = atLeastOneRowDeleted
    End Sub
    Private Sub ToggleCheckState(ByVal checkState As Boolean)
        ' Iterate through the Products.Rows property
        For Each row As GridViewRow In Products.Rows
            ' Access the CheckBox
            Dim cb As CheckBox = row.FindControl("ProductSelector")
            If cb IsNot Nothing Then
                cb.Checked = checkState
            End If
        Next
    End Sub
    Protected Sub CheckAll_Click(sender As Object, e As EventArgs) _
        Handles CheckAll.Click
        ToggleCheckState(True)
    End Sub
    Protected Sub UncheckAll_Click(sender As Object, e As EventArgs) _
        Handles UncheckAll.Click
        ToggleCheckState(False)
    End Sub
End Class

После копирования декларативной разметки и исходного кода уделите время тестированию BatchDelete.aspx через браузер. Вы увидите список первых десяти продуктов в представлении GridView, где в каждой строке перечислены имя продукта, категория и цена, а также установлен флажок. Должны быть три кнопки: "Выбрать все", "Снять выделение со всех" и "Удалить выбранные товары". При нажатии кнопки "Выбрать все" выделяются все флажки, а кнопка "Снять все" убирает выделение со всех флажков. При нажатии кнопки "Удалить выбранные продукты" отображается сообщение, которое содержит ProductID значения выбранных продуктов, но не удаляет продукты.

Интерфейс из CheckBoxField.aspx был перемещен в BatchDeleting.aspx

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

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

После успешного копирования интерфейса пакетного удаления на BatchDeleting.aspx остается только обновить код, чтобы кнопка "Удалить выбранные продукты" удаляла отмеченные продукты с помощью метода DeleteProductsWithTransaction в классе ProductsBLL. Этот метод, добавленный в учебник «Обертка изменений базы данных внутри транзакции», принимает List(Of T) значений ProductID в качестве входных данных и удаляет каждый из соответствующих ProductID в рамках транзакции.

Обработчик DeleteSelectedProducts событий Button Click в настоящее время использует следующий For Each цикл для итерации каждой строки GridView:

' Iterate through the Products.Rows property
For Each row As GridViewRow In Products.Rows
    ' Access the CheckBox
    Dim cb As CheckBox = row.FindControl("ProductSelector")
    If cb IsNot Nothing AndAlso cb.Checked Then
        ' Delete row! (Well, not really...)
        atLeastOneRowDeleted = True
        ' First, get the ProductID for the selected row
        Dim productID As Integer = _
            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 ...
        ' Dim productAPI As New ProductsBLL
        ' productAPI.DeleteProduct(productID)
        '............................................
    End If
Next

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

Указанный выше код на самом деле не удаляет записи, так как вызов метода класса ProductsBLLDelete закомментирован. Если эта логика удаления будет применена, код удалит продукты, но не в рамках атомарной операции. То есть, если первые несколько удалений в последовательности выполнены успешно, но более позднее удаление завершилось неудачно (возможно, из-за нарушения ограничения внешнего ключа), будет выброшено исключение, но те продукты, которые уже были удалены, останутся удаленными.

Чтобы обеспечить атомарность, необходимо вместо этого использовать ProductsBLL метод класса DeleteProductsWithTransaction . Так как этот метод принимает список значений ProductID , необходимо сначала скомпилировать этот список из сетки, а затем передать его в качестве параметра. Сначала мы создадим экземпляр List(Of T) типа Integer. Внутри For Each цикла нам нужно добавить выбранные значения продуктов ProductID к этому List(Of T). После выполнения цикла этот List(Of T) должен быть передан методу ProductsBLL класса DeleteProductsWithTransaction. Обновите обработчик событий для кнопки DeleteSelectedProducts с помощью следующего кода: Click

Protected Sub DeleteSelectedProducts_Click(sender As Object, e As EventArgs) _
    Handles DeleteSelectedProducts.Click
    
    ' Create a List to hold the ProductID values to delete
    Dim productIDsToDelete As New System.Collections.Generic.List(Of Integer)
    ' Iterate through the Products.Rows property
    For Each row As GridViewRow In Products.Rows
        ' Access the CheckBox
        Dim cb As CheckBox = CType(row.FindControl("ProductSelector"), CheckBox)
        If cb IsNot Nothing AndAlso cb.Checked Then
            ' Save the ProductID value for deletion
            ' First, get the ProductID for the selected row
            Dim productID As Integer = _
                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)
        End If
    Next
    ' Call the DeleteProductsWithTransaction method and show the Label 
    ' if at least one row was deleted...
    If productIDsToDelete.Count > 0 Then
        Dim productAPI As New ProductsBLL()
        productAPI.DeleteProductsWithTransaction(productIDsToDelete)
        DeleteResults.Visible = True
        ' Rebind the data to the GridView
        Products.DataBind()
    End If
End Sub

Обновленный код создает объект List(Of T) типа Integer (productIDsToDelete) и заполняет его значениями ProductID, которые нужно удалить. После цикла, если выбран по крайней мере один продукт, вызывается метод For Each класса ProductsBLL, и ему передается этот список. DeleteResults Метка также отображается, а данные возвращаются в GridView (чтобы только что удаленные записи больше не отображались как строки в сетке).

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

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

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

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

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

Замечание

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

Сводка

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

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

Счастливое программирование!

Сведения о авторе

Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга - "Sams: Изучаем ASP.NET 2.0 за 24 часа". Его можно достичь по адресу mitchell@4GuysFromRolla.com.

Особое спасибо кому

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