一括更新 (VB)

作成者: Scott Mitchell

PDF のダウンロード

1 回の操作で複数のデータベース レコードを更新する方法について説明します。 ユーザー インターフェイス レイヤーでは、各行が編集可能な GridView を作成します。 データ アクセス層では、トランザクション内で複数の更新操作をラップして、すべての更新が成功するか、すべての更新プログラムがロールバックされるようにします。

はじめに

前の チュートリアル では、データ アクセス層を拡張してデータベース トランザクションのサポートを追加する方法について説明しました。 データベース トランザクションでは、一連のデータ変更ステートメントが 1 つのアトミック操作として扱われることが保証されます。これにより、すべての変更が失敗するか、すべて成功します。 この低レベルの DAL 機能を使用すると、バッチ データ変更インターフェイスの作成に注意を向ける準備が整いました。

このチュートリアルでは、各行が編集可能な GridView を構築します (図 1 を参照)。 各行は編集インターフェイスでレンダリングされるため、[編集]、[更新]、[キャンセル] ボタンの列は必要ありません。 代わりに、ページ上に 2 つの [製品の更新] ボタンがあり、クリックすると GridView 行を列挙し、データベースを更新します。

GridView の各行は編集可能です

図 1: GridView の各行は編集可能です (クリックするとフルサイズの画像が表示されます)

始めましょう。

注意

バッチ更新の実行に関するチュートリアルでは、DataList コントロールを使用してバッチ編集インターフェイスを作成しました。 このチュートリアルは、GridView を使用する前のチュートリアルとは異なり、バッチ更新はトランザクションのスコープ内で実行されます。 このチュートリアルを完了したら、前のチュートリアルに戻り、前のチュートリアルで追加したデータベース トランザクション関連の機能を使用するように更新することをお勧めします。

すべての GridView 行を編集可能にする手順の確認

データの挿入、更新、削除の概要 」チュートリアルで説明したように、GridView では、基になるデータを行ごとに編集するための組み込みのサポートが提供されます。 内部的には、GridView では、そのプロパティを使用してEditIndex編集可能な行が記録されます。 GridView はデータ ソースにバインドされるときに、各行をチェックして、行のインデックスが の EditIndex値と等しいかどうかを確認します。 その場合、その行のフィールドは編集インターフェイスを使用してレンダリングされます。 BoundFields の場合、編集インターフェイスは TextBox であり、その Text プロパティには BoundField の DataField プロパティで指定されたデータ フィールドの値が割り当てられます。 TemplateFields では、 EditItemTemplate の代わりに が使用されます ItemTemplate

ユーザーが行の [編集] ボタンをクリックすると、編集ワークフローが開始されることを思い出してください。 これによりポストバックが発生し、GridView の EditIndex プロパティがクリックされた行のインデックスに設定され、データがグリッドに再バインドされます。 行の [キャンセル] ボタンがクリックされると、ポストバック時に、 EditIndex はグリッドにデータを再バインドする前に の -1 値に設定されます。 GridView の行は 0 からインデックス作成を開始するため、 を に-1設定EditIndexすると、GridView が読み取り専用モードで表示されます。

プロパティは EditIndex 行ごとの編集には適していますが、バッチ編集用には設計されていません。 GridView 全体を編集可能にするには、編集インターフェイスを使用して各行をレンダリングする必要があります。 これを実現する最も簡単な方法は、 で定義された編集インターフェイスを使用して、編集可能な各フィールドが TemplateField として実装される場所を ItemTemplate作成することです。

次のいくつかの手順では、完全に編集可能な GridView を作成します。 手順 1 では、まず GridView とその ObjectDataSource を作成し、その BoundFields と CheckBoxField を TemplateFields に変換します。 手順 2 と 3 では、編集インターフェイスを TemplateFields EditItemTemplate からその ItemTemplate インターフェイスに移動します。

手順 1: 製品情報の表示

行が編集可能な GridView の作成について心配する前に、まず製品情報を表示します。 フォルダー内のBatchUpdate.aspxページをBatchData開き、GridView をツールボックスからDesignerにドラッグします。 GridView を IDProductsGrid 設定し、そのスマート タグから、 という名前 ProductsDataSourceの新しい ObjectDataSource にバインドすることを選択します。 クラスの GetProducts メソッドからデータを取得するように ObjectDataSource をProductsBLL構成します。

ProductsBLL クラスを使用するように ObjectDataSource を構成する

図 2: クラスを使用するように ObjectDataSource を構成する ProductsBLL (クリックするとフルサイズの画像が表示されます)

GetProducts メソッドを使用して製品データを取得する

図 3: メソッドを使用して製品データを取得する GetProducts (クリックするとフルサイズの画像が表示されます)

GridView と同様に、ObjectDataSource の変更機能は行ごとに機能するように設計されています。 レコードのセットを更新するには、データをバッチ処理して BLL に渡すコードを ASP.NET ページの分離コード クラスに少し記述する必要があります。 したがって、ObjectDataSource の UPDATE タブ、INSERT タブ、DELETE タブのドロップダウン リストを (None) に設定します。 [完了] をクリックしてウィザードを終了します。

UPDATE タブ、INSERT タブ、DELETE タブの Drop-Down Lists を に設定します (なし)

図 4: UPDATE、INSERT、および DELETE タブの Drop-Down Lists を に設定します ([なし] をクリックすると、フルサイズの画像が表示されます)

データ ソースの構成ウィザードを完了すると、ObjectDataSource の宣言型マークアップは次のようになります。

<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>

また、データ ソースの構成ウィザードを完了すると、Visual Studio で GridView の製品データ フィールドに対して BoundFields と CheckBoxField が作成されます。 このチュートリアルでは、ユーザーが製品の名前、カテゴリ、価格、および廃止された状態のみを表示および編集できるようにします。 、UnitPriceCategoryNameおよび Discontinued 以外ProductNameのフィールドをすべて削除し、最初の 3 つのフィールドのプロパティの名前をそれぞれ Product、Category、Price に変更HeaderTextします。 最後に、GridView のスマート タグの [ページングを有効にする] チェック ボックスと [並べ替えを有効にする] チェック ボックスをチェックします。

この時点で、GridView には 3 つの BoundField (ProductName、、 CategoryName) と UnitPriceCheckBoxField (Discontinued) があります。 これらの 4 つのフィールドを TemplateFields に変換し、編集インターフェイスを TemplateFields EditItemTemplate から その ItemTemplateに移動する必要があります。

注意

「データ変更インターフェイスのカスタマイズ」チュートリアルで TemplateFields の作成とカスタマイズについて説明しました。 BoundFields と CheckBoxField を TemplateFields に変換し、編集インターフェイス ItemTemplate を定義する手順について説明しますが、スタックしたり、リフレッシャーが必要な場合は、この前のチュートリアルを参照してください。

GridView のスマート タグで、[列の編集] リンクをクリックして [フィールド] ダイアログ ボックスを開きます。 次に、各フィールドを選択し、[このフィールドを TemplateField に変換する] リンクをクリックします。

既存の BoundFields と CheckBoxField を TemplateFields に変換する

図 5: 既存の BoundFields と CheckBoxField を TemplateFields に変換する

各フィールドが TemplateField になったので、編集インターフェイスを s から EditItemTemplate s に移動する ItemTemplate 準備ができました。

手順 2: インターフェイスのProductNameUnitPrice作成、およびDiscontinued編集

、、および Discontinued 編集インターフェイスのProductNameUnitPrice作成は、この手順のトピックであり、各インターフェイスが TemplateField でEditItemTemplate既に定義されているため、非常に簡単です。 該当するカテゴリの CategoryName DropDownList を作成する必要があるため、編集インターフェイスの作成にはもう少し関係があります。 この CategoryName 編集インターフェイスは、手順 3 で取り組みます。

TemplateField から始 ProductName めましょう。 GridView のスマート タグから [テンプレートの編集] リンクをクリックし、TemplateFields EditItemTemplateProductNameドリルダウンします。 [テキスト ボックス] を選択し、クリップボードにコピーし、TemplateFields ItemTemplateProductName貼り付けます。 TextBox の プロパティを IDProductName変更します。

次に、 に RequiredFieldValidator を ItemTemplate 追加して、ユーザーが各製品名の値を確実に指定できるようにします。 プロパティを ControlToValidate ProductName に設定し、 プロパティを ErrorMessage に設定します。製品の名前を指定する必要があります。 および プロパティを Text * に指定します。 にこれらの追加を行った後、 ItemTemplate画面は図 6 のようになります。

ProductName TemplateField に TextBox と RequiredFieldValidator が含まれるようになりました

図 6: ProductName TemplateField に TextBox と RequiredFieldValidator が含まれるようになりました (フルサイズの画像を表示するには、ここをクリックします)

編集インターフェイスの場合は UnitPrice 、まず TextBox を から EditItemTemplateItemTemplateコピーします。 次に、TextBox の前に $ を配置し、その ID プロパティを UnitPrice に設定し、その Columns プロパティを 8 に設定します。

また、 に CompareValidator を追加してUnitPriceItemTemplate、ユーザーが入力した値が $0.00 以上の有効な通貨値であることを確認します。 検証コントロールの ControlToValidate プロパティを UnitPrice に設定し、その ErrorMessage プロパティを [有効な通貨値を入力する必要があります] に設定します。 通貨記号は省略してください。、そのTextプロパティは *、プロパティは に、Typeプロパティは OperatorCurrencyGreaterThanEqual、プロパティValueToCompareは 0 です。

CompareValidator を追加して、入力した価格が負以外の通貨値であることを確認します

図 7: CompareValidator を追加して、入力した価格が負以外の通貨値であることを確認する (フルサイズの画像を表示する をクリックします)

Discontinued TemplateField の場合は、 で既に定義されている CheckBox をItemTemplate使用できます。 を ID Discontinued に設定し、そのプロパティを EnabledTrue設定するだけです。

手順 3: 編集インターフェイスのCategoryName作成

TemplateFields EditItemTemplateCategoryName編集インターフェイスには、データ フィールドの値を表示する TextBox がCategoryName含まれています。 これを、可能なカテゴリを一覧表示する DropDownList に置き換える必要があります。

注意

「データ変更インターフェイスのカスタマイズ」チュートリアルでは、TextBox ではなく DropDownList を含むようにテンプレートをカスタマイズする方法について詳しく説明します。 ここでの手順は完了していますが、簡潔に示されています。 カテゴリ DropDownList の作成と構成の詳細については、 データ変更インターフェイスのカスタマイズ に関するチュートリアルを参照してください。

DropDownList をツールボックスから TemplateFields ItemTemplateにドラッグしCategoryName、 を IDCategories設定します。 この時点では、通常、スマート タグを使用して DropDownLists のデータ ソースを定義し、新しい ObjectDataSource を作成します。 ただし、これにより 内に ObjectDataSource ItemTemplateが追加され、その結果、GridView 行ごとに ObjectDataSource インスタンスが作成されます。 代わりに、GridView の TemplateFields の外部に ObjectDataSource を作成してみましょう。 テンプレートの編集を終了し、ObjectDataSource をツールボックスから ObjectDataSource の下のDesignerにProductsDataSourceドラッグします。 新しい ObjectDataSource CategoriesDataSource に名前を付け、クラス s GetCategories メソッドをCategoriesBLL使用するように構成します。

CategoriesBLL クラスを使用するように ObjectDataSource を構成する

図 8: クラスを使用するように ObjectDataSource を構成する CategoriesBLL (クリックするとフルサイズの画像が表示されます)

GetCategories メソッドを使用してカテゴリ データを取得する

図 9: メソッドを使用してカテゴリ データを取得する GetCategories (クリックするとフルサイズの画像が表示されます)

この ObjectDataSource は単にデータを取得するために使用されるため、UPDATE タブと DELETE タブのドロップダウン リストを (None) に設定します。 [完了] をクリックしてウィザードを終了します。

[UPDATE] タブと [DELETE] タブの Drop-Down Lists を [(なし)] に設定します

図 10: UPDATE タブと DELETE タブの Drop-Down Lists を に設定します ([なし] をクリックすると、フルサイズの画像が表示されます)

ウィザードを完了すると、 CategoriesDataSource 宣言型マークアップは次のようになります。

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

CategoriesDataSource作成して構成したら、TemplateField にItemTemplate戻りCategoryName、DropDownList のスマート タグから [データ ソースの選択] リンクをクリックします。 [データ ソースの構成] ウィザードで、最初のCategoriesDataSourceドロップダウン リストからオプションを選択し、表示とCategoryID値として使用したCategoryNameオプションを選択します。

DropDownList を CategoriesDataSource にバインドする

図 11: DropDownList を に CategoriesDataSource バインドする (クリックするとフルサイズの画像が表示されます)

この時点で、 Categories DropDownList はすべてのカテゴリを一覧表示しますが、GridView 行にバインドされている製品の適切なカテゴリはまだ自動的には選択されません。 これを実現するには、DropDownList を製品のSelectedValueCategoryID値に設定Categoriesする必要があります。 図 12 に示すように、DropDownList のスマート タグから [Edit DataBindings]\(DataBindings の編集\) リンクをクリックし、プロパティをCategoryIDデータ フィールドに関連付けますSelectedValue

Product の CategoryID 値を DropDownList の SelectedValue プロパティにバインドする

図 12: 製品の CategoryID 値を DropDownList s SelectedValue プロパティにバインドする

最後の問題の 1 つが残っています。製品に値が指定されていない CategoryID 場合は、 の SelectedValue databinding ステートメントによって例外が発生します。 これは、DropDownList にはカテゴリの項目のみが含まれており、 のデータベース値CategoryIDを持つNULL製品にはオプションが提供されないためです。 これを解決するには、DropDownList の AppendDataBoundItems プロパティを に True 設定し、宣言構文から プロパティを省略して Value 、DropDownList に新しい項目を追加します。 つまり、DropDownList の宣言型構文が Categories 次のようになっていることを確認します。

<asp:DropDownList ID="Categories" runat="server" AppendDataBoundItems="True" 
    DataSourceID="CategoriesDataSource" DataTextField="CategoryName" 
    DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'>
    <asp:ListItem Value=">-- Select One --</asp:ListItem>
</asp:DropDownList>

<asp:ListItem Value=""> -- Select One -- の属性がValue空の文字列に明示的に設定されていることに注意してください。 ケースを処理NULLするためにこの追加の DropDownList 項目が必要な理由と、空の文字列へのプロパティの割り当てが不可欠な理由については、データ変更インターフェイスValueカスタマイズに関するチュートリアルを参照してください。

注意

ここには、言及する価値がある潜在的なパフォーマンスとスケーラビリティの問題があります。 各行には データ ソースとして を CategoriesDataSource 使用する DropDownList があるため、 CategoriesBLL クラスの GetCategories メソッドはページ訪問ごとに n 回呼び出されます。ここで、 n は GridView 内の行数です。 これらの n は を呼び出して GetCategories 、データベースに 対する n 個 のクエリを生成します。 このデータベースへの影響は、返されたカテゴリを要求ごとのキャッシュにキャッシュするか、SQL キャッシュ依存関係または非常に短い時間ベースの有効期限を使用してキャッシュレイヤーを介してキャッシュすることで軽減される可能性があります。

手順 4: 編集インターフェイスの完了

進行状況を表示するために一時停止せずに、GridView のテンプレートに対していくつかの変更を行いました。 ブラウザーを使用して進行状況を確認してください。 図 13 に示すように、各行は、セルの編集インターフェイスを含む を使用して ItemTemplateレンダリングされます。

各 GridView 行は編集可能です

図 13: 各 GridView 行は編集可能です (クリックするとフルサイズの画像が表示されます)

この時点で対処する必要がある小さな書式設定の問題がいくつかあります。 最初に、値に UnitPrice 4 つの小数点が含まれていることに注意してください。 これを解決するには、TemplateFields ItemTemplateUnitPrice戻り、TextBox のスマート タグから [Edit DataBindings]\(DataBindings の編集\) リンクをクリックします。 次に、プロパティを Text 数値として書式設定するように指定します。

Text プロパティを数値として書式設定する

図 14: プロパティを Text 数値として書式設定する

次に、(左揃えではなく) 列の Discontinued チェック ボックスを中央に配置します。 GridView のスマート タグから [列の編集] をクリックし、左下隅にあるフィールドの一覧から [TemplateField] を選択 Discontinued します。 図 15 に示すように、ドリルダウン ItemStyle して プロパティを HorizontalAlign Center に設定します。

廃止されたチェック ボックスを中央揃えする

図 15: CheckBox を中央揃えするDiscontinued

次に、ValidationSummary コントロールをページに追加し、その ShowMessageBox プロパティを に True 、その ShowSummary プロパティを に False設定します。 また、ボタン Web コントロールを追加します。このコントロールをクリックすると、ユーザーの変更が更新されます。 具体的には、GridView の上と下の 2 つのボタン Web コントロールを追加し、両方のコントロールの Text プロパティを Update Products に設定します。

GridView の編集インターフェイスは TemplateFields ItemTemplate で定義されているため、 EditItemTemplate s は余分であり、削除される可能性があります。

上記の書式設定を変更し、Button コントロールを追加し、不要 EditItemTemplate な を削除すると、ページの宣言構文は次のようになります。

<p>
    <asp:Button ID="UpdateAllProducts1" runat="server" Text="Update Products" />
</p>
<p>
    <asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False" 
        DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
        AllowPaging="True" AllowSorting="True">
        <Columns>
            <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
                <ItemTemplate>
                    <asp:TextBox ID="ProductName" runat="server" 
                        Text='<%# Bind("ProductName") %>'></asp:TextBox>
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
                        ControlToValidate="ProductName"
                        ErrorMessage="You must provide the product's name." 
                        runat="server">*</asp:RequiredFieldValidator>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Category" 
                SortExpression="CategoryName">
                <ItemTemplate>
                    <asp:DropDownList ID="Categories" runat="server" 
                        AppendDataBoundItems="True" 
                        DataSourceID="CategoriesDataSource"
                        DataTextField="CategoryName" 
                        DataValueField="CategoryID" 
                        SelectedValue='<%# Bind("CategoryID") %>'>
                        <asp:ListItem>-- Select One --</asp:ListItem>
                    </asp:DropDownList>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Price" 
                SortExpression="UnitPrice">
                <ItemTemplate>
                    $<asp:TextBox ID="UnitPrice" runat="server" Columns="8" 
                        Text='<%# Bind("UnitPrice", "{0:N}") %>'></asp:TextBox>
                    <asp:CompareValidator ID="CompareValidator1" runat="server" 
                        ControlToValidate="UnitPrice"
                        ErrorMessage="You must enter a valid currency value. 
                                      Please omit any currency symbols."
                        Operator="GreaterThanEqual" Type="Currency" 
                        ValueToCompare="0">*</asp:CompareValidator>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
                <ItemTemplate>
                    <asp:CheckBox ID="Discontinued" runat="server" 
                        Checked='<%# Bind("Discontinued") %>' />
                </ItemTemplate>
                <ItemStyle HorizontalAlign="Center" />
            </asp:TemplateField>
        </Columns>
    </asp:GridView>
</p>
<p>
    <asp:Button ID="UpdateAllProducts2" runat="server" Text="Update Products" />
    <asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}"
        SelectMethod="GetProducts" TypeName="ProductsBLL">
    </asp:ObjectDataSource>
    <asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}"
        SelectMethod="GetCategories" TypeName="CategoriesBLL">
    </asp:ObjectDataSource>
    <asp:ValidationSummary ID="ValidationSummary1" runat="server" 
        ShowMessageBox="True" ShowSummary="False" />
</p>

図 16 は、ボタン Web コントロールが追加され、書式設定が変更された後にブラウザーで表示された場合のこのページを示しています。

ページに 2 つの [製品の更新] ボタンが含まれるようになりました

図 16: ページに 2 つの更新プログラム製品ボタンが含まれるようになりました (クリックするとフルサイズの画像が表示されます)

手順 5: 製品の更新

ユーザーがこのページにアクセスすると、変更を加え、2 つの [製品の更新] ボタンのいずれかをクリックします。 その時点で、行ごとにユーザーが入力した値をインスタンスに ProductsDataTable 保存し、それを BLL メソッドに渡し、その ProductsDataTable インスタンスを DAL メソッド UpdateWithTransaction に渡す必要があります。 前のチュートリアルで作成した メソッドをUpdateWithTransaction使用すると、変更のバッチがアトミック操作として更新されます。

で という名前 BatchUpdateBatchUpdate.aspx.vb メソッドを作成し、次のコードを追加します。

Private Sub BatchUpdate()
    ' Enumerate the GridView's Rows collection and create a ProductRow
    Dim productsAPI As New ProductsBLL()
    Dim products As Northwind.ProductsDataTable = productsAPI.GetProducts()
    For Each gvRow As GridViewRow In ProductsGrid.Rows
        ' Find the ProductsRow instance in products that maps to gvRow
        Dim productID As Integer = _
            Convert.ToInt32(ProductsGrid.DataKeys(gvRow.RowIndex).Value)
        Dim product As Northwind.ProductsRow = products.FindByProductID(productID)
        If product IsNot Nothing Then
            ' Programmatically access the form field elements in the 
            ' current GridViewRow
            Dim productName As TextBox = _
                CType(gvRow.FindControl("ProductName"), TextBox)
            Dim categories As DropDownList = _
                CType(gvRow.FindControl("Categories"), DropDownList)
            Dim unitPrice As TextBox = _
                CType(gvRow.FindControl("UnitPrice"), TextBox)
            Dim discontinued As CheckBox = _
                CType(gvRow.FindControl("Discontinued"), CheckBox)
            ' Assign the user-entered values to the current ProductRow
            product.ProductName = productName.Text.Trim()
            If categories.SelectedIndex = 0 Then 
                product.SetCategoryIDNull() 
            Else 
                product.CategoryID = Convert.ToInt32(categories.SelectedValue)
            End If
            If unitPrice.Text.Trim().Length = 0 Then 
                product.SetUnitPriceNull() 
            Else 
                product.UnitPrice = Convert.ToDecimal(unitPrice.Text)
            End If
            product.Discontinued = discontinued.Checked
        End If
    Next
    ' Now have the BLL update the products data using a transaction
    productsAPI.UpdateWithTransaction(products)
End Sub

このメソッドは、まず、BLL s GetProducts メソッドの呼び出しを介して、すべての製品を に戻ProductsDataTableすことから始まります。 次に、GridView のコレクションをProductGridRows列挙します。 コレクションにはRows、GridView にGridViewRow表示される各行のインスタンスが含まれています。 ページごとに最大 10 行が表示されるため、GridView のコレクションには 10 個以下の Rows 項目が含まれます。

各行に対して、 ProductID がコレクションからDataKeys取得され、 からProductsDataTable適切な ProductsRow が選択されます。 4 つの TemplateField 入力コントロールは、プログラムによって参照され、その値はインスタンスのプロパティに ProductsRow 割り当てられます。 各 GridView 行の値を使用して を ProductsDataTable更新した後、BLL s UpdateWithTransaction メソッドに渡されます。これは、前のチュートリアルで説明したように、DAL メソッド UpdateWithTransaction を呼び出すだけです。

このチュートリアルで使用されるバッチ更新アルゴリズムは、製品の ProductsDataTable 情報が変更されているかどうかに関係なく、GridView の行に対応する の各行を更新します。 このようなブラインド更新は通常、パフォーマンスの問題ではありませんが、データベース テーブルの変更を監査すると、余分なレコードが発生する可能性があります。 バッチ更新の実行に関するチュートリアルに戻り、DataList を使用してバッチ更新インターフェイスを調べ、ユーザーが実際に変更したレコードのみを更新するコードを追加しました。 必要に応じて、Batch 更新 の実行に関するページの手法を自由に使用して、このチュートリアルのコードを更新してください。

注意

スマート タグを使用してデータ ソースを GridView にバインドすると、Visual Studio によってデータ ソースの主キー値が GridView の DataKeyNames プロパティに自動的に割り当てられます。 手順 1 で説明したように、GridView のスマート タグを使用して ObjectDataSource を GridView にバインドしなかった場合は、コレクションを通じてDataKeys各行の値にアクセスProductIDするために、GridView の DataKeyNames プロパティを ProductID に手動で設定する必要があります。

BatchUpdate使用されるコードは、BLL メソッドUpdateProductで使用されるコードと似ていますが、メイン違いは、メソッド内で UpdateProduct 1 つのProductRowインスタンスのみがアーキテクチャから取得されることです。 のProductRowプロパティを割り当てるコードは、 メソッドと のループ内For Eachのコードの間UpdateProductsBatchUpdate、全体的なパターンと同じです。

このチュートリアルを完了するには、いずれかの [製品の BatchUpdate 更新] ボタンがクリックされたときに メソッドを呼び出す必要があります。 これら 2 つの Button コントロールのイベントのイベント ハンドラー Click を作成し、イベント ハンドラーに次のコードを追加します。

BatchUpdate()
ClientScript.RegisterStartupScript(Me.GetType(), "message", _
    "alert('The products have been updated.');", True)

最初に に対する呼び出し BatchUpdateが行われます。 次に、 プロパティをClientScript使用して JavaScript を挿入し、製品が更新されましたと読み取るメッセージ ボックスを表示します。

このコードをテストするには、少し時間がかかります。 ブラウザーを使用してアクセス BatchUpdate.aspx し、複数の行を編集し、[Update Products]\(製品の更新\) ボタンのいずれかをクリックします。 入力検証エラーがないと仮定すると、"製品が更新されました" というメッセージ ボックスが表示されます。 更新プログラムの原子性を確認するには、1234.56 の値を許可しないUnitPriceようなランダムCHECK制約を追加することを検討してください。 次に から BatchUpdate.aspx、複数のレコードを編集し、製品 UnitPrice の値の 1 つを禁止値 ( 1234.56) に設定します。 これにより、バッチ操作中に他の変更が元の値にロールバックされた状態で [製品の更新] をクリックするとエラーが発生します。

代替BatchUpdateメソッド

先ほど調べたメソッドはBatchUpdate、BLL メソッドGetProductsからすべての製品を取得し、GridView に表示されるレコードのみを更新します。 この方法は、GridView がページングを使用しない場合に最適ですが、ページングが行われる場合は、数百、数千、または数万の製品が存在する可能性がありますが、GridView には 10 行しかありません。 このような場合、データベースからすべての製品を 10 個変更するだけでは理想的ではありません。

このような状況では、代わりに次 BatchUpdateAlternate のメソッドを使用することを検討してください。

Private Sub BatchUpdateAlternate()
    ' Enumerate the GridView's Rows collection and create a ProductRow
    Dim productsAPI As New ProductsBLL()
    Dim products As New Northwind.ProductsDataTable()
    For Each gvRow As GridViewRow In ProductsGrid.Rows
        ' Create a new ProductRow instance
        Dim productID As Integer = _
            Convert.ToInt32(ProductsGrid.DataKeys(gvRow.RowIndex).Value)
        Dim currentProductDataTable As Northwind.ProductsDataTable = _
            productsAPI.GetProductByProductID(productID)
        If currentProductDataTable.Rows.Count > 0 Then
            Dim product As Northwind.ProductsRow = currentProductDataTable(0)
            Dim productName As TextBox = _
                CType(gvRow.FindControl("ProductName"), TextBox)
            Dim categories As DropDownList = _
                CType(gvRow.FindControl("Categories"), DropDownList)
            Dim unitPrice As TextBox = _
                CType(gvRow.FindControl("UnitPrice"), TextBox)
            Dim discontinued As CheckBox = _
                CType(gvRow.FindControl("Discontinued"), CheckBox)
            ' Assign the user-entered values to the current ProductRow
            product.ProductName = productName.Text.Trim()
            If categories.SelectedIndex = 0 Then 
                product.SetCategoryIDNull() 
            Else 
                product.CategoryID = Convert.ToInt32(categories.SelectedValue)
            End If
            If unitPrice.Text.Trim().Length = 0 Then 
                product.SetUnitPriceNull() 
            Else 
                product.UnitPrice = Convert.ToDecimal(unitPrice.Text)
            End If
            product.Discontinued = discontinued.Checked
            ' Import the ProductRow into the products DataTable
            products.ImportRow(product)
        End If
    Next
    ' Now have the BLL update the products data using a transaction
    productsAPI.UpdateProductsWithTransaction(products)
End Sub

BatchMethodAlternateは、 という名前productsの新しい空ProductsDataTableの を作成することによって開始されます。 次に、GridView の Rows コレクションをステップ実行し、各行に対して BLL メソッドを使用して特定の GetProductByProductID(productID) 製品情報を取得します。 取得したProductsRowインスタンスのプロパティは と同じ方法BatchUpdateで更新されますが、行を更新すると、DataTable の ImportRow(DataRow) メソッドを介して にproductsProductsDataTableインポートされます。

ループが For Each 完了すると、 products GridView の各行に対して 1 つの ProductsRow インスタンスが含まれます。 各インスタンスは ProductsRow (更新されるのではなく) に products 追加されているため、それをメソッドに盲目的に渡 UpdateWithTransaction すと、 ProductsTableAdapter は各レコードをデータベースに挿入しようとします。 代わりに、これらの各行が変更されたことを指定する必要があります (追加されていません)。

これは、 という名前 UpdateProductsWithTransactionの BLL に新しいメソッドを追加することで実現できます。 UpdateProductsWithTransactionを次に示します。 内ProductsDataTableの各インスタンスの ProductsRow を にModified設定RowStateし、 を DAL メソッドUpdateWithTransactionに渡ProductsDataTableします。

Public Function UpdateProductsWithTransaction _
    (ByVal products As Northwind.ProductsDataTable) As Integer
    ' Mark each product as Modified
    products.AcceptChanges()
    For Each product As Northwind.ProductsRow In products
        product.SetModified()
    Next
    ' Update the data via a transaction
    Return UpdateWithTransaction(products)
End Function

まとめ

GridView には、行ごとの組み込みの編集機能が用意されていますが、完全に編集可能なインターフェイスを作成するためのサポートがありません。 このチュートリアルで説明したように、このようなインターフェイスは可能ですが、少しの作業が必要です。 すべての行が編集可能な GridView を作成するには、GridView のフィールドを TemplateFields に変換し、 内で編集インターフェイスを定義する ItemTemplate 必要があります。 さらに、Update All -type Button Web コントロールは、GridView とは別にページに追加する必要があります。 これらの Buttons Click イベント ハンドラーは、GridView の Rows コレクションを列挙し、変更を に ProductsDataTable格納し、更新された情報を適切な BLL メソッドに渡す必要があります。

次のチュートリアルでは、バッチ削除用のインターフェイスを作成する方法について説明します。 特に、各 GridView 行にはチェック ボックスが含まれており、[すべての種類の更新] ボタンの代わりに、[選択した行の削除] ボタンが表示されます。

プログラミングに満足!

著者について

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

特別な感謝

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