1 回の操作で複数のデータベース レコードを削除する方法について説明します。 ユーザー インターフェイス レイヤーでは、前のチュートリアルで作成した強化された GridView を基に構築します。 データ アクセス層では、トランザクション内で複数の削除操作をラップして、すべての削除が成功するか、すべての削除がロールバックされるようにします。
イントロダクション
前のチュートリアルでは、完全に編集可能な GridView を使用してバッチ編集インターフェイスを作成する方法について説明しました。 ユーザーが一度に多くのレコードを一度に編集する状況では、バッチ編集インターフェイスで必要なポストバックとキーボードからマウスへのコンテキスト スイッチがはるかに少なくなり、エンド ユーザーの効率が向上します。 この手法は、ユーザーが一度に多数のレコードを削除するのが一般的なページでも同様に便利です。
オンライン メール クライアントを使用したユーザーは、最も一般的なバッチ削除インターフェイスの 1 つである、対応する [すべてのチェック済みアイテムの削除] ボタンを含むグリッド内の各行のチェック ボックスに既に精通しています (図 1 を参照)。 このチュートリアルは、Web ベースのインターフェイスと、一連のレコードを 1 つのアトミック操作として削除するメソッドの両方を作成する前のチュートリアルのすべてのハード作業を既に行っているため、かなり短いです。
「チェックボックスの GridView 列の追加」チュートリアルでは、チェックボックスの列を含む GridView を作成し、「トランザクション内のデータベース変更の折り返し」チュートリアルで、トランザクションを使用してList<T>
値のProductID
を削除するメソッドを BLL で作成しました。 このチュートリアルでは、前のエクスペリエンスを基に構築し、マージして、実際のバッチ削除の例を作成します。
図 1: 各行にチェック ボックスが含まれています (フルサイズの画像を表示する場合はクリックします)
手順 1: バッチ削除インターフェイスの作成
「チェックボックスの GridView 列の追加」チュートリアルでバッチ削除インターフェイスを既に作成しているため、最初から作成するのではなく、BatchDelete.aspx
にコピーするだけです。 まず、BatchDelete.aspx
フォルダーのBatchData
ページと、CheckBoxField.aspx
フォルダー内の EnhancedGridView
ページを開きます。
CheckBoxField.aspx
ページからソース ビューに移動し、図 2 に示すように、<asp:Content>
タグ間でマークアップをコピーします。
図 2: CheckBoxField.aspx
の宣言型マークアップをクリップボードにコピーする (フルサイズの画像を表示する をクリックします)
次に、 BatchDelete.aspx
のソース ビューに移動し、 <asp:Content>
タグ内にクリップボードの内容を貼り付けます。 また、CheckBoxField.aspx.vb
の分離コード クラス内からBatchDelete.aspx.vb
の分離コード クラス内にコードをコピーして貼り付けます (DeleteSelectedProducts
Button のClick
イベント ハンドラー、ToggleCheckState
メソッド、およびClick
およびCheckAll
Buttons のUncheckAll
イベント ハンドラー)。 このコンテンツをコピーした後、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 に最初の 10 個の製品が一覧表示され、各行に製品名、カテゴリ、価格がチェックボックスと共に一覧表示されます。 [すべてオン]、[すべてオフ]、[選択した製品の削除] の 3 つのボタンが必要です。 [すべてチェック]ボタンをクリックするとすべてのチェックボックスが選択され、[すべてオフ]はすべてのチェックボックスをオフにします。 [選択した製品の削除] をクリックすると、選択した製品の 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 Web コントロールがプログラムによって参照されます。 オンにすると、ProductID
コレクションから行のDataKeys
が取得され、DeleteResults
Label のText
プロパティが更新され、その行が削除対象として選択されたことを示すメッセージが含まれます。
上記のコードでは、 ProductsBLL
クラスの Delete
メソッドの呼び出しがコメント アウトされるため、実際にはレコードは削除されません。この削除ロジックを適用すると、コードはアトミック操作内ではなく製品を削除します。 つまり、シーケンス内の最初のいくつかの削除が成功したが、後で失敗した場合 (おそらく外部キー制約違反が原因)、例外がスローされますが、既に削除された製品は削除されたままです。
原子性を確保するには、代わりに ProductsBLL
クラスの DeleteProductsWithTransaction
メソッドを使用する必要があります。 このメソッドは ProductID
値のリストを受け取るため、最初にグリッドからこのリストをコンパイルしてから、パラメーターとして渡す必要があります。 最初に、List(Of T)
型のInteger
のインスタンスを作成します。
For Each
ループ内で、選択した製品ProductID
値をこのList(Of T)
に追加する必要があります。 ループの後、この List(Of T)
を ProductsBLL
クラスの DeleteProductsWithTransaction
メソッドに渡す必要があります。
DeleteSelectedProducts
Button 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
ループの後に、少なくとも 1 つの製品が選択されている場合、ProductsBLL
クラスの DeleteProductsWithTransaction
メソッドが呼び出され、このリストが渡されます。
DeleteResults
ラベルも表示され、データは GridView にリバインドされます (新しく削除されたレコードがグリッド内の行として表示されなくなります)。
図 4 は、複数の行が削除対象として選択された後の GridView を示しています。 図 5 は、[選択した製品の削除] ボタンがクリックされた直後の画面を示しています。 図 5 では、削除されたレコードの ProductID
値が GridView の下のラベルに表示され、それらの行は GridView に表示されなくなります。
図 4: 選択した製品が削除されます (フルサイズの画像を表示する をクリックします)
図 5: 削除された製品 ProductID
値が GridView の下に一覧表示されます (フルサイズの画像を表示する をクリックします)。
注
DeleteProductsWithTransaction
メソッドのアトミック性をテストするには、Order Details
テーブルに製品のエントリを手動で追加し、その製品を (他のユーザーと共に) 削除します。 関連する注文を含む製品を削除しようとすると、外部キー制約違反が発生しますが、選択した他の製品の削除がどのようにロールバックされるかに注意してください。
概要
バッチ削除インターフェイスを作成するには、チェック ボックスの列とボタン Web コントロールを含む GridView を追加する必要があります。ボタン Web コントロールをクリックすると、選択したすべての行が 1 つのアトミック操作として削除されます。 このチュートリアルでは、前の 2 つのチュートリアル「 チェックボックスの GridView 列の追加 」と「 トランザクション内のデータベース変更の折り返し」で行った作業をまとめて、このようなインターフェイスを構築しました。 最初のチュートリアルでは、チェック ボックスの列を含む GridView を作成し、後者では、List(Of T)
値のProductID
を渡すと、トランザクションのスコープ内でそれらをすべて削除するメソッドを BLL に実装しました。
次のチュートリアルでは、バッチ挿入を実行するためのインターフェイスを作成します。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジを使用しています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・セルフ ASP.NET 24時間で2.0です。 彼にはmitchell@4GuysFromRolla.comを通じて連絡できます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、ヒルトン ギセナウとテレサ マーフィーでした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、mitchell@4GuysFromRolla.comにご連絡ください。