作成者 Scott Mitchell
1 回の操作で複数のデータベース レコードを更新する方法について説明します。 ユーザー インターフェイス レイヤーでは、各行が編集可能な GridView を構築します。 データ アクセス層では、トランザクション内で複数の更新操作をラップして、すべての更新が成功するか、すべての更新がロールバックされるようにします。
イントロダクション
前の チュートリアル では、データ アクセス層を拡張してデータベース トランザクションのサポートを追加する方法について説明しました。 データベース トランザクションでは、一連のデータ変更ステートメントが 1 つのアトミック操作として扱われることが保証されます。これにより、すべての変更が失敗するか、すべて成功します。 低レベルの DAL 機能が片付いたので、私たちはバッチデータ変更インターフェースの作成に注意を向ける準備ができました。
このチュートリアルでは、各行が編集可能な GridView を作成します (図 1 を参照)。 各行は編集インターフェイスでレンダリングされるため、[編集]、[更新]、[キャンセル] ボタンの列は必要ありません。 代わりに、ページ上に 2 つの [Update Products]\(製品の更新\) ボタンがあります。このボタンをクリックすると、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 からインデックス作成を開始するため、 EditIndex
を -1
に設定すると、GridView が読み取り専用モードで表示されます。
EditIndex
プロパティは行ごとの編集には適していますが、バッチ編集用には設計されていません。 GridView 全体を編集可能にするには、編集インターフェイスを使用して各行をレンダリングする必要があります。 これを実現する最も簡単な方法は、編集可能な各フィールドが、 ItemTemplate
で定義された編集インターフェイスを使用して TemplateField として実装される場所を作成することです。
次のいくつかの手順で、完全に編集可能な GridView を作成します。 手順 1 では、まず GridView とその ObjectDataSource を作成し、BoundFields と CheckBoxField を TemplateFields に変換します。 手順 2 と 3 では、編集インターフェイスを TemplateFields EditItemTemplate
から ItemTemplate
に移動します。
手順 1: 製品情報の表示
行が編集可能な GridView の作成について心配する前に、まず製品情報を表示します。
BatchUpdate.aspx
フォルダーのBatchData
ページを開き、ツールボックスからデザイナーに GridView をドラッグします。 GridView の ID
を ProductsGrid
に設定し、スマート タグから、 ProductsDataSource
という名前の新しい ObjectDataSource にバインドすることを選択します。
ProductsBLL
クラスの GetProducts
メソッドからデータを取得するように ObjectDataSource を構成します。
図 2: ProductsBLL
クラスを使用するように ObjectDataSource を構成する (フルサイズの画像を表示する をクリックします)。
図 3: GetProducts
メソッドを使用して製品データを取得する (フルサイズの画像を表示する をクリックします)。
GridView と同様に、ObjectDataSource の変更機能は行ごとに機能するように設計されています。 レコードのセットを更新するには、データをバッチ処理して BLL に渡すコードを ASP.NET ページの分離コード クラスに少し記述する必要があります。 そのため、ObjectDataSource の [UPDATE]、[INSERT]、[DELETE] タブのドロップダウン リストを [なし] に設定します。 [完了] をクリックして、ウィザードを完了します。
図 4: [UPDATE]、[INSERT]、[DELETE] タブの [Drop-Down リスト] を [なし] に設定する (フルサイズの画像を表示する 場合はクリックします)
データ ソースの構成ウィザードを完了すると、ObjectDataSource の宣言型マークアップは次のようになります。
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
また、データ ソースの構成ウィザードを完了すると、Visual Studio で GridView の製品データ フィールドの BoundFields と CheckBoxField が作成されます。 このチュートリアルでは、製品の名前、カテゴリ、価格、および廃止された状態の表示と編集のみをユーザーに許可します。
ProductName
、CategoryName
、UnitPrice
、Discontinued
の各フィールドを除くすべてのフィールドを削除し、最初の 3 つのフィールドのHeaderText
プロパティの名前をそれぞれ Product、Category、Price に変更します。 最後に、GridView のスマート タグの [ページングの有効化] チェック ボックスと [並べ替えを有効にする] チェック ボックスをオンにします。
この時点で、GridView には 3 つの BoundField (ProductName
、 CategoryName
、 UnitPrice
) と CheckBoxField (Discontinued
) があります。 これら 4 つのフィールドを TemplateFields に変換し、編集インターフェイスを TemplateField の EditItemTemplate
からその ItemTemplate
に移動する必要があります。
注
データ変更インターフェイスのカスタマイズチュートリアルで TemplateFields の作成とカスタマイズについて説明しました。 BoundFields と CheckBoxField を TemplateFields に変換し、それらの ItemTemplate
で編集インターフェイスを定義する各ステップをガイドします。もし途中で行き詰まったり、復習が必要になった場合は、以前のチュートリアルをぜひ参照してください。
GridView のスマート タグで、[列の編集] リンクをクリックして [フィールド] ダイアログ ボックスを開きます。 次に、各フィールドを選択し、[このフィールドを TemplateField に変換] リンクをクリックします。
図 5: 既存の BoundFields と CheckBoxField を TemplateField に変換する
各フィールドが TemplateField になったので、編集インターフェイスを EditItemTemplate
から ItemTemplate
に移動する準備ができました。
手順 2: ProductName
、UnitPrice
、およびDiscontinued
のインターフェイスを作成し編集する
ProductName
、UnitPrice
、およびDiscontinued
編集インターフェイスの作成は、この手順のトピックであり、各インターフェイスは TemplateField のEditItemTemplate
で既に定義されているため、非常に簡単です。
CategoryName
編集インターフェイスの作成は、該当するカテゴリの DropDownList を作成する必要があるため、もう少し複雑です。 この CategoryName
編集インターフェイスは、手順 3 で取り組みます。
ProductName
TemplateField から始めましょう。 GridView のスマート タグから [テンプレートの編集] リンクをクリックし、 ProductName
TemplateField の EditItemTemplate
にドリルダウンします。 テキスト ボックスを選択してクリップボードにコピーし、 ProductName
TemplateField の ItemTemplate
に貼り付けます。 TextBox の ID
プロパティを ProductName
に変更します。
次に、RequiredFieldValidator を ItemTemplate
に追加して、ユーザーが各製品名の値を確実に指定できるようにします。
ControlToValidate
プロパティを ProductName に設定し、ErrorMessage
プロパティを [製品の名前を指定する必要があります] に設定します。 *に Text
プロパティを指定します。
ItemTemplate
にこれらの追加を行った後、画面は図 6 のようになります。
図 6: ProductName
TemplateField には、テキスト ボックスと RequiredFieldValidator が含まれています (フルサイズの画像を表示する をクリックします)。
UnitPrice
編集インターフェイスの場合は、まずテキスト ボックスをEditItemTemplate
からItemTemplate
にコピーします。 次に、TextBox の前に $ を配置し、 ID
プロパティを UnitPrice に設定し、 Columns
プロパティを 8 に設定します。
また、 UnitPrice
の ItemTemplate
に CompareValidator を追加して、ユーザーが入力した値が $0.00 以上の有効な通貨値であることを確認します。 検証コントロールの ControlToValidate
プロパティを UnitPrice に設定し、その ErrorMessage
プロパティには「有効な通貨値を入力してください」というメッセージを設定します。 通貨記号は省略してください。それぞれのプロパティについて、Text
プロパティを*に、Type
プロパティをCurrency
に、Operator
プロパティをGreaterThanEqual
に、そしてValueToCompare
プロパティを0に設定してください。
図 7: CompareValidator を追加して、入力された価格が負以外の通貨値であることを確認する (フルサイズの画像を表示する をクリックします)
Discontinued
TemplateField では、ItemTemplate
で既に定義されている CheckBox を使用できます。
ID
を Discontinued に設定し、Enabled
プロパティを true
に設定するだけです。
手順 3: 編集インターフェイスCategoryName
を作成する
CategoryName
TemplateFields EditItemTemplate
の編集インターフェイスには、CategoryName
データ フィールドの値を表示する TextBox が含まれています。 これを、考えられるカテゴリを一覧表示する DropDownList に置き換える必要があります。
注
データ変更インターフェイスのカスタマイズに関するチュートリアルでは、TextBox ではなく DropDownList を含むようにテンプレートをカスタマイズする方法について詳しく説明します。 ここでの手順は完了していますが、簡潔に示されています。 カテゴリ DropDownList の作成と構成の詳細については、「 データ変更インターフェイスのカスタマイズ 」チュートリアルを参照してください。
ツールボックスから CategoryName
TemplateField の ItemTemplate
に DropDownList をドラッグし、その ID
を Categories
に設定します。 この時点では、通常、スマート タグを使用して DropDownLists のデータ ソースを定義し、新しい ObjectDataSource を作成します。 ただし、これにより、 ItemTemplate
内に ObjectDataSource が追加され、その結果、GridView 行ごとに ObjectDataSource インスタンスが作成されます。 代わりに、GridView の TemplateFields の外部に ObjectDataSource を作成しましょう。 テンプレートの編集を終了し、ツールボックスから ProductsDataSource
ObjectDataSource の下にあるデザイナーに ObjectDataSource をドラッグします。 新しい ObjectDataSource CategoriesDataSource
に名前を付け、 CategoriesBLL
クラスの GetCategories
メソッドを使用するように構成します。
図 8: CategoriesBLL
クラスを使用するように ObjectDataSource を構成する (フルサイズの画像を表示する をクリックします)
図 9: GetCategories
メソッドを使用してカテゴリ データを取得します (フルサイズの画像を表示する をクリックします)。
この ObjectDataSource は単にデータを取得するために使用されるため、[UPDATE] タブと [DELETE] タブのドロップダウン リストを [なし] に設定します。 [完了] をクリックして、ウィザードを完了します。
図 10: [更新] タブと [削除] タブの Drop-Down リストを [なし] に設定します (フルサイズの画像を表示する 場合はクリックします)
ウィザードを完了すると、 CategoriesDataSource
の宣言型マークアップは次のようになります。
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
CategoriesDataSource
を作成して構成したら、CategoryName
TemplateField のItemTemplate
に戻り、DropDownList のスマート タグから [データ ソースの選択] リンクをクリックします。 データ ソース構成ウィザードで、最初のドロップダウン リストから CategoriesDataSource
オプションを選択し、 CategoryName
表示に使用し、値として CategoryID
することを選択します。
図 11: DropDownList を CategoriesDataSource
にバインドする (フルサイズの画像を表示する をクリックします)
この時点で、 Categories
DropDownList にはすべてのカテゴリが一覧表示されますが、GridView 行にバインドされている製品の適切なカテゴリはまだ自動的には選択されません。 これを実現するには、 Categories
DropDownList の SelectedValue
を製品の CategoryID
値に設定する必要があります。 DropDownList のスマート タグから [DataBindings の編集] リンクをクリックし、図 12 に示すように、 SelectedValue
プロパティを CategoryID
データ フィールドに関連付けます。
図 12: 製品の CategoryID
値を DropDownList の SelectedValue
プロパティにバインドする
最後の問題の 1 つが残っています。製品に CategoryID
値が指定されていない場合、 SelectedValue
の databinding ステートメントによって例外が発生します。 これは、DropDownList にはカテゴリのアイテムのみが含まれており、NULL
のCategoryID
データベース値を持つ製品にはオプションが提供されないためです。 これを解決するには、DropDownList の AppendDataBoundItems
プロパティを true
に設定し、新しい項目を DropDownList に追加します。宣言型構文から Value
プロパティを省略します。 つまり、 Categories
DropDownList の宣言構文が次のようになっていることを確認します。
<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
属性が空の文字列に明示的に設定されていることに注意してください。
ケースを処理するためにこの追加の DropDownList 項目が必要な理由と、空の文字列への NULL
プロパティの割り当てが不可欠な理由については、「Value
」チュートリアルを参照してください。
注
ここには、言及する価値がある潜在的なパフォーマンスとスケーラビリティの問題があります。 各行には CategoriesDataSource
をデータ ソースとして使用する DropDownList があるため、 CategoriesBLL
クラスの GetCategories
メソッドはページアクセスごとに n 回呼び出されます 。n は GridView の行数です。 これらの n 個の GetCategories
呼び出しは、データベースに対する n 個 のクエリになります。 このデータベースへの影響は、返されたカテゴリを要求ごとのキャッシュにキャッシュするか、SQL キャッシュ依存関係または非常に短い時間ベースの有効期限を使用してキャッシュ層を介してキャッシュすることで軽減される可能性があります。
手順 4: 編集インターフェイスの完了
進行状況を表示するために一時停止することなく、GridView のテンプレートに多数の変更を加えた。 少し時間を取って、ブラウザーで進捗を確認してみます。 図 13 に示すように、各行はセルの編集インターフェイスを含む ItemTemplate
を使用してレンダリングされます。
図 13: 各 GridView 行は編集可能です (フルサイズの画像を表示する をクリックします)
この時点で対処する必要がある小さな書式設定の問題がいくつかあります。 最初に、 UnitPrice
値には 4 つの小数点が含まれていることに注意してください。 これを修正するには、 UnitPrice
TemplateField の ItemTemplate
に戻り、TextBox のスマート タグから [DataBindings の編集] リンクをクリックします。 次に、 Text
プロパティを数値として書式設定するように指定します。
図 14: Text
プロパティを数値として書式設定する
次に、(左揃えではなく) Discontinued
列のチェック ボックスを中央に配置します。 GridView のスマート タグから [列の編集] をクリックし、左下隅にあるフィールドの一覧から Discontinued
TemplateField を選択します。 図 15 に示すように、 ItemStyle
にドリルダウンし、 HorizontalAlign
プロパティを Center に設定します。
図 15: Discontinued
CheckBox を中央揃えする
次に、ValidationSummary コントロールをページに追加し、その ShowMessageBox
プロパティを true
に設定し、その ShowSummary
プロパティを false
に設定します。 また、ボタン Web コントロールを追加します。このコントロールをクリックすると、ユーザーの変更が更新されます。 具体的には、GridView の上と下の 2 つのボタン Web コントロールを追加し、両方のコントロール Text
プロパティを Update Products に設定します。
GridView の編集インターフェイスは TemplateFields ItemTemplate
で定義されているため、 EditItemTemplate
は余分であり、削除される可能性があります。
上記の書式設定を変更し、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 コントロールが追加され、書式設定が変更された後にブラウザーで表示された場合のこのページを示しています。
図 16: ページに 2 つの更新プログラム製品ボタンが含まれるようになりました (フルサイズの画像を表示する をクリックします)
手順 5: 製品の更新
ユーザーがこのページにアクセスすると、変更を加え、2 つの [製品の更新] ボタンのいずれかをクリックします。 その時点で、ユーザーが入力した各行の値を何らかの方法で ProductsDataTable
インスタンスに保存し、それを BLL メソッドに渡し、その ProductsDataTable
インスタンスを DAL の UpdateWithTransaction
メソッドに渡す必要があります。
UpdateWithTransaction
で作成した メソッドを使用すると、変更のバッチがアトミック操作として更新されます。
BatchUpdate
に BatchUpdate.aspx.cs
という名前のメソッドを作成し、次のコードを追加します。
private void BatchUpdate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Find the ProductsRow instance in products that maps to gvRow
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsRow product = products.FindByProductID(productID);
if (product != null)
{
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateWithTransaction(products);
}
このメソッドは、BLL s ProductsDataTable
メソッドの呼び出しを使用して、すべての製品をGetProducts
に戻することから始めます。 次に、 ProductGrid
GridView の Rows
コレクションを列挙します。
Rows
コレクションには、GridView に表示される各行のGridViewRow
インスタンスが含まれています。 1 ページあたり最大 10 行が表示されるため、GridView の Rows
コレクションには 10 個以下の項目が含まれます。
各行に対して、 ProductID
は DataKeys
コレクションから取得され、適切な ProductsRow
が ProductsDataTable
から選択されます。 4 つの TemplateField 入力コントロールは、プログラムによって参照され、その値が ProductsRow
インスタンスのプロパティに割り当てられます。 各GridView行の値がProductsDataTable
を更新するために使用された後、その結果がBLLのUpdateWithTransaction
メソッドに渡されます。これは、前のチュートリアルで見たように、単にDALのUpdateWithTransaction
メソッドを呼び出すだけです。
このチュートリアルで使用されるバッチ更新アルゴリズムは、製品の情報が変更されたかどうかに関係なく、GridView の行に対応する ProductsDataTable
の各行を更新します。 通常、このようなブラインド更新はパフォーマンスの問題にはなりませんが、データベース テーブルの変更を監査している場合、余計なレコードが増えてしまう可能性があります。
バッチ更新の実行チュートリアルに戻り、DataList を使用してバッチ更新インターフェイスを調べ、ユーザーが実際に変更したレコードのみを更新するコードを追加しました。 必要に応じて、 バッチ更新を実行する 方法を自由に使用して、このチュートリアルのコードを更新してください。
注
スマート タグを使用してデータ ソースを GridView にバインドすると、Visual Studio によって、データ ソースの主キー値が GridView の DataKeyNames
プロパティに自動的に割り当てられます。 手順 1 で説明したように GridView のスマート タグを使用して ObjectDataSource を GridView にバインドしなかった場合は、DataKeyNames
コレクションを通じて各行のProductID
値にアクセスするために、GridView の DataKeys
プロパティを ProductID に手動で設定する必要があります。
BatchUpdate
で使用されるコードは、BLL s UpdateProduct
メソッドで使用されるコードと似ています。主な違いは、UpdateProduct
メソッドではアーキテクチャから 1 つのProductRow
インスタンスのみが取得されることです。
ProductRow
のプロパティを割り当てるコードは、UpdateProducts
メソッドと、foreach
のBatchUpdate
ループ内のコードの間で、全体的なパターンと同じです。
このチュートリアルを完了するには、[Update Products]\(製品の更新\) ボタンのいずれかがクリックされたときに BatchUpdate
メソッドを呼び出す必要があります。 これら 2 つの Button コントロールの Click
イベントのイベント ハンドラーを作成し、イベント ハンドラーに次のコードを追加します。
BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message",
"alert('The products have been updated.');", true);
最初に、 BatchUpdate
に対して呼び出しが行われます。 次に、 ClientScript property
を使用して JavaScript を挿入し、製品が更新されたことを示すメッセージ ボックスを表示します。
このコードをテストするには、少し時間がかかります。 ブラウザーから BatchUpdate.aspx
にアクセスし、複数の行を編集して、[Update Products]\(製品の更新\) ボタンのいずれかをクリックします。 入力検証エラーがないと仮定すると、製品が更新されたことを示すメッセージ ボックスが表示されます。 更新プログラムのアトミック性を確認するには、ランダムな CHECK
制約 (1234.56 の UnitPrice
値を許可しない制約など) を追加することを検討してください。 次に、 BatchUpdate.aspx
から複数のレコードを編集し、製品の UnitPrice
値の 1 つを許可されていない値 (1234.56) に設定します。 これにより、そのバッチ操作中に他の変更が元の値にロールバックされた状態で [Update Products]\(製品の更新\) をクリックするとエラーが発生します。
代替方法BatchUpdate
ここで調べたBatchUpdate
メソッドは、BLL の メソッドからGetProducts
製品を取得し、GridView に表示されるレコードのみを更新します。 この方法は、GridView がページングを使用しない場合に最適ですが、使用する場合は、数百、数千、または数万の製品が存在する可能性がありますが、GridView には 10 行しかありません。 このような場合、データベースからすべての製品を取得して、そのうちの 10 個のみを変更することは理想的ではありません。
このような状況の場合は、代わりに次の BatchUpdateAlternate
メソッドを使用することを検討してください。
private void BatchUpdateAlternate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Create a new ProductRow instance
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsDataTable currentProductDataTable =
productsAPI.GetProductByProductID(productID);
if (currentProductDataTable.Rows.Count > 0)
{
Northwind.ProductsRow product = currentProductDataTable[0];
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
// Import the ProductRow into the products DataTable
products.ImportRow(product);
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateProductsWithTransaction(products);
}
BatchMethodAlternate
最初に、ProductsDataTable
という名前の新しい空のproducts
を作成します。 次に、GridView の Rows
コレクションをステップ実行し、各行に対して BLL s GetProductByProductID(productID)
メソッドを使用して特定の製品情報を取得します。 取得したProductsRow
インスタンスのプロパティは、BatchUpdate
と同じ方法で更新されますが、行を更新した後、DataTable の ImportRow(DataRow)
を使用してにインポートされます。
foreach
ループが完了すると、products
には GridView の各行に対して 1 つのProductsRow
インスタンスが含まれます。
ProductsRow
の各インスタンスは (更新ではなく) products
に追加されているため、UpdateWithTransaction
メソッドに盲目的に渡すと、ProductsTableAdapter
は各レコードをデータベースに挿入しようとします。 代わりに、これらの各行が変更されたことを指定する必要があります (追加されません)。
これを行うには、 UpdateProductsWithTransaction
という名前の BLL に新しいメソッドを追加します。
UpdateProductsWithTransaction
次に示すように、RowState
内の各ProductsRow
インスタンスのProductsDataTable
をModified
に設定し、dal のProductsDataTable
メソッドにUpdateWithTransaction
を渡します。
public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
// Mark each product as Modified
products.AcceptChanges();
foreach (Northwind.ProductsRow product in products)
product.SetModified();
// Update the data via a transaction
return UpdateWithTransaction(products);
}
概要
GridView には、行ごとの組み込みの編集機能が用意されていますが、完全に編集可能なインターフェイスを作成するためのサポートがありません。 このチュートリアルで説明したように、このようなインターフェイスは可能ですが、少し作業が必要です。 すべての行が編集可能な GridView を作成するには、GridView のフィールドを TemplateFields に変換し、 ItemTemplate
内で編集インターフェイスを定義する必要があります。 さらに、Update All -type Button Web コントロールは、GridView とは別にページに追加する必要があります。 これらの Buttons Click
イベント ハンドラーは、GridView の Rows
コレクションを列挙し、変更を ProductsDataTable
に格納し、更新された情報を適切な BLL メソッドに渡す必要があります。
次のチュートリアルでは、バッチ削除用のインターフェイスを作成する方法について説明します。 具体的には、各 GridView 行にはチェック ボックスが含まれます。[すべての -type を更新] ボタンの代わりに、[選択した行の削除] ボタンがあります。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジを使用しています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・セルフ ASP.NET 24時間で2.0です。 彼には mitchell@4GuysFromRolla.comで連絡できます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルの校閲者はテレサ・マーフィーとデイヴィッド・スルでした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、mitchell@4GuysFromRolla.comにメッセージを送ってください。