一括削除 (C#)

作成者: Scott Mitchell

PDF のダウンロード

1 回の操作で複数のデータベース レコードを削除する方法について説明します。 ユーザー インターフェイス レイヤーでは、前のチュートリアルで作成した強化された GridView を基に構築します。 データ アクセス層では、トランザクション内で複数の削除操作をラップして、すべての削除が成功するか、すべての削除がロールバックされるようにします。

はじめに

前のチュートリアルでは、完全に編集可能な GridView を使用してバッチ編集インターフェイスを作成する方法について説明しました。 ユーザーが一度に多くのレコードを編集する状況では、バッチ編集インターフェイスで必要なポストバックとキーボードからマウスへのコンテキスト切替が大幅に少なくなり、エンド ユーザーの作業効率が向上します。 この手法は、ユーザーが一度に多くのレコードを削除するのが一般的なページでも、同様に有効です。

オンライン メール クライアントを使用したユーザーは、最も一般的なバッチ削除インターフェイスの 1 つである、グリッドの各行にチェックボックスがあり、対応する [チェックされた項目をすべて削除] ボタンがあるインターフェイスに既に精通しています (図 1 を参照)。 このチュートリアルは、Web ベースのインターフェイスと、一連のレコードを 1 つのアトミック操作として削除するメソッドの両方を作成する前のチュートリアルのすべてのハード作業を既に行っているため、かなり短いです。 チェックボックスの GridView 列を追加するチュートリアルでは、チェックボックスの列を含む GridView を作成しました。トランザクション内のデータベース変更をラップするのチュートリアルでは、トランザクションを使用して ProductID 値の List<T> を削除するメソッドを BLL で作成しました。 ここでは、前のチュートリアルを基に構築し、マージして、実際のバッチ削除の例を作成します。

Each Row Includes a Checkbox

図 1: 各行に含まれるチェック ボックス (クリックするとフルサイズの画像が表示されます)

手順 1: バッチ削除インターフェイスの作成

チェックボックスの GridView 列を追加するのチュートリアルでバッチ削除インターフェイスを既に作成しているため、最初から作成するのではなく、単に BatchDelete.aspx へコピーできます。 まず、BatchData フォルダー内の BatchDelete.aspx ページと EnhancedGridView フォルダー内の CheckBoxField.aspx ページを開きます。 CheckBoxField.aspx ページからソース ビューに移動し、図 2 に示すように <asp:Content> のタグ間でマークアップをコピーします。

Copy the Declarative Markup of CheckBoxField.aspx to the Clipboard

図 2: CheckBoxField.aspx の宣言型マークアップをクリップボードにコピーする (クリックするとフルサイズの画像が表示されます)

次に、BatchDelete.aspx でソース ビューに移動し、クリップボードの内容を <asp:Content> タグ内に貼り付けます。 また、CheckBoxField.aspx.cs の分離コード クラス内のコードを BatchDelete.aspx.cs の分離コード クラス内にコピーして貼り付けます (DeleteSelectedProducts ボタンの Click イベント ハンドラーと ToggleCheckState メソッド、CheckAll ボタンと UncheckAll ボタンの Click イベント ハンドラー)。 このコンテンツをコピーした後、BatchDelete.aspx ページの分離コード クラスには次のコードが含まれている必要があります。

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 に最初の 10 個の製品が一覧表示され、各行に製品名、カテゴリ、価格がチェックボックスと共に一覧表示されます。 [Check All]、[Uncheck All]、[Delete Selected Products] の 3 つのボタンが必要です。 [Check All] ボタンをクリックするとすべてのチェックボックスが選択され、[Uncheck All]はすべてのチェックボックスをオフにします。 [Delete Selected Products] をクリックすると、選択した製品の ProductID 値を 一覧表示するメッセージが表示されますが、実際には製品は削除されません。

The Interface from CheckBoxField.aspx has been Moved to BatchDeleting.aspx

図 3: CheckBoxField.aspx のインターフェイスが BatchDeleting.aspx に移動 (クリックするとフルサイズの画像が表示されます)

手順 2: トランザクションを使用してチェックされた製品を削除する

バッチ削除インターフェイスが正常に BatchDeleting.aspx にコピーされると、あとは、ProductsBLL クラスの DeleteProductsWithTransaction メソッドを使って、選択された商品の削除ボタンがチェックされた商品を削除するようにコードを更新するだけです。 トランザクション内のデータベース変更をラップするチュートリアルで追加されたこのメソッドは、入力として ProductIDList<T> 値を受け取り、トランザクションの範囲内で対応する ProductID をそれぞれ削除します。

DeleteSelectedProducts ボタン 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);
        //............................................
    }
}

各行に対して、ProductSelector チェックボックス Web コントロールがプログラムによって参照されます。 チェックボックスをオンにすると、行 の ProductIDDataKeys コレクションから取得され、DeleteResults ラベルの Text プロパティは、行が削除対象として選択されたことを示すメッセージが含むよう更新されます。

上記のコードでは、ProductsBLL クラスの Delete メソッドの呼び出しがコメント アウトされるため、実際にはレコードは削除されません。この削除ロジックを適用すると、コードはアトミック操作内ではなく製品を削除します。 つまり、シーケンス内の最初のいくつかの削除が成功したが、後の削除が失敗した場合 (おそらく外部キー制約違反が原因)、例外がスローされますが、既に削除された製品は削除されたままです。

アトミック性を確保するために、代わりに ProductsBLL クラスの DeleteProductsWithTransaction メソッドを使用する必要があります。 このメソッドは ProductID 値のリストを受け入れるので、最初にグリッドからこのリストをコンパイルし、パラメーターとして渡す必要があります。 最初に、型 intList<T> のインスタンスを作成します。 foreach ループ内で、選択した製品の ProductID 値をこの List<T> に追加する必要があります。 ループの後、List<T>ProductsBLL クラスの DeleteProductsWithTransaction メソッドに渡す必要があります。 DeleteSelectedProducts ボタンの 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();
    }
}

更新されたコードでは、int型 (productIDsToDelete) の List<T> が作成され、それには削除する ProductID 値が入ります。 foreach ループの後に、少なくとも 1 つの製品が選択されている場合、 ProductsBLL クラスの DeleteProductsWithTransaction メソッドが呼び出され、このリストが渡されます。 DeleteResults ラベルも表示され、データが GridView にリバインドされます (新しく削除されたレコードがグリッド内の行として表示されなくなります)。

図 4 は、複数の行が削除対象として選択された後の GridView を示しています。 図 5 は、[Delete Selected Products] ボタンがクリックされた直後の画面を示しています。 図 5 では、削除されたレコードの ProductID 値は GridView の下のラベルに表示され、それらの行は GridView に表示されなくなります。

The Selected Products Will Be Deleted

図 4: 選択した製品が削除される (クリックするとフルサイズの画像が表示されます)

The Deleted Products ProductID Values are Listed Beneath the GridView

図 5: 削除された製品の ProductID 値が GridView の下に一覧表示される (クリックするとフルサイズの画像が表示されます)

Note

DeleteProductsWithTransaction メソッドのアトミック性をテストするには、Order Details テーブルに製品のエントリを手動で追加し、その製品を (他と共に) 削除します。 関連する注文を含む製品を削除しようとすると、外部キー制約違反が発生しますが、選択した他の製品の削除がどのようにロールバックされるかに注意してください。

まとめ

バッチ削除インターフェイスを作成するには、チェック ボックスの列とボタン Web コントロールを含む GridView を追加する必要があります。ボタン Web コントロールをクリックすると、選択したすべての行が 1 つのアトミック操作として削除されます。 このチュートリアルでは、前の 2 つのチュートリアル、チェックボックスの GridView 列を追加するトランザクション内のデータベース変更をラップするで行った作業をまとめて、このようなインターフェイスを構築しました。 最初のチュートリアルでは、チェックボックスの列を含む GridView を作成しました。後者では、ProductID 値の List<T> を渡す際に、トランザクションのスコープ内でそれらをすべて削除するメソッドを BLL に実装しました。

次のチュートリアルでは、バッチ挿入を実行するためのインターフェイスを作成します。

プログラミングに満足!

著者について

Scott Mitchell は、7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者です。1998 年から Microsoft の Web テクノロジに携わっています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのレビュー リーダーは、Hilton Giesenow と Teresa Murphy でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。