Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Узнайте, как удалить несколько записей базы данных в одной операции. На уровне пользовательского интерфейса мы создадим расширенный 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.
Рис. 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
значения выбранных продуктов, но не удаляет продукты.
Рис. 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
обновляется, чтобы включить сообщение, указывающее, что строка была выбрана для удаления.
Указанный выше код на самом деле не удаляет записи, так как вызов метода класса ProductsBLL
Delete
закомментирован. Если эта логика удаления будет применена, код удалит продукты, но не в рамках атомарной операции. То есть, если первые несколько удалений в последовательности выполнены успешно, но более позднее удаление завершилось неудачно (возможно, из-за нарушения ограничения внешнего ключа), будет выброшено исключение, но те продукты, которые уже были удалены, останутся удаленными.
Чтобы обеспечить атомарность, необходимо вместо этого использовать 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. Выбранные продукты будут удалены (щелкните, чтобы просмотреть изображение полного размера)
Рис. 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.