一括挿入 (C#)
1 回の操作で複数のデータベース レコードを挿入する方法について説明します。 ユーザー インターフェイス レイヤーでは、GridView を拡張して、ユーザーが複数の新しいレコードを入力できるようにします。 データ アクセス層では、トランザクション内で複数の挿入操作をラップして、すべての挿入が成功するか、すべての挿入がロールバックされるようにします。
はじめに
Batch Updating チュートリアルでは、GridView コントロールをカスタマイズして、複数のレコードが編集可能なインターフェイスを表示する方法について説明しました。 ページにアクセスするユーザーは一連の変更を行い、1 回のボタンクリックでバッチ更新を実行できます。 ユーザーが一度に多くのレコードを一度に更新する場合、このようなインターフェイスは、「 データの挿入、更新、削除の概要 」チュートリアルで最初に確認した既定の行ごとの編集機能と比較して、数え切れないクリックとキーボードからマウスへのコンテキスト スイッチを保存できます。
この概念は、レコードを追加するときにも適用できます。 ここで Northwind Traders では、特定のカテゴリに対して多数の製品を含むサプライヤーから出荷を受け取ることがよくあります。 例えば、東京トレーダーズから6種類の紅茶とコーヒーの商品が出荷される場合があります。 ユーザーが DetailsView コントロールを使用して 6 つの製品を一度に 1 つずつ入力する場合、同じ値の多くを何度も選択する必要があります。同じカテゴリ (飲料)、同じ仕入先 (東京トレーダー)、同じ廃止値 (False)、注文値 (0) の同じ単位を選択する必要があります。 この繰り返しデータ入力には時間がかかるだけでなく、エラーが発生しやすくなります。
少しの作業で、ユーザーが仕入先とカテゴリを 1 回選択し、一連の製品名と単価を入力し、ボタンをクリックして新しい製品をデータベースに追加できるようにするバッチ挿入インターフェイスを作成できます (図 1 を参照)。 各製品が追加されると、その ProductName
フィールドと UnitPrice
データ フィールドには TextBoxes に入力された値が割り当てられ、その CategoryID
値と SupplierID
値にはフォームの上部にある DropDownLists の値が割り当てられます。 と UnitsOnOrder
のDiscontinued
値はそれぞれ、 と 0 のfalse
ハードコーディングされた値に設定されます。
図 1: バッチ挿入インターフェイス (クリックするとフルサイズの画像が表示されます)
このチュートリアルでは、図 1 に示すバッチ挿入インターフェイスを実装するページを作成します。 前の 2 つのチュートリアルと同様に、トランザクションのスコープ内で挿入をラップして原子性を確保します。 始めましょう。
手順 1: 表示インターフェイスを作成する
このチュートリアルは、表示領域と挿入領域の 2 つの領域に分割された 1 つのページで構成されます。 この手順で作成する表示インターフェイスには、GridView に製品が表示され、[製品出荷の処理] という名前のボタンが含まれています。 このボタンをクリックすると、表示インターフェイスが挿入インターフェイスに置き換えられます(図 1 を参照)。 表示インターフェイスは、[出荷から製品を追加] または [キャンセル] ボタンをクリックした後に戻ります。 手順 2 で挿入インターフェイスを作成します。
一度に 1 つだけ表示される 2 つのインターフェイスを持つページを作成する場合、各インターフェイスは通常、他のコントロールのコンテナーとして機能する Panel Web コントロール内に配置されます。 したがって、このページには、インターフェイスごとに 1 つの 2 つのパネル コントロールがあります。
まず、フォルダー内のページをBatchInsert.aspx
BatchData
開き、ツールボックスからDesignerにパネルをドラッグします (図 2 を参照)。 Panel s プロパティを ID
に DisplayInterface
設定します。 パネルをDesignerに追加すると、そのHeight
プロパティと Width
プロパティはそれぞれ 50px と 125px に設定されます。 プロパティ ウィンドウからこれらのプロパティ値をクリアします。
図 2: ツールボックスからDesignerにパネルをドラッグする (フルサイズの画像を表示する をクリックします)
次に、Button コントロールと GridView コントロールをパネルにドラッグします。 Button s ID
プロパティを に ProcessShipment
設定し、そのプロパティを Text
[Process Product Shipment]\(製品出荷の処理\) に設定します。 GridView の ID
プロパティを に ProductsGrid
設定し、そのスマート タグから という名前 ProductsDataSource
の新しい ObjectDataSource にバインドします。 ObjectDataSource を構成して、クラスの GetProducts
メソッドからデータをProductsBLL
プルします。 この GridView はデータの表示にのみ使用されるため、UPDATE タブ、INSERT タブ、DELETE タブのドロップダウン リストを (None) に設定します。 [完了] をクリックして、データ ソースの構成ウィザードを完了します。
図 3: クラスの GetProducts
メソッドから返されたデータをProductsBLL
表示する (フルサイズの画像を表示する をクリックします)
図 4: UPDATE、INSERT、および DELETE タブの Drop-Down Lists を に設定します ([なし] をクリックすると、フルサイズの画像が表示されます)
ObjectDataSource ウィザードを完了すると、Visual Studio によって、製品データ フィールドに BoundFields と CheckBoxField が追加されます。 、CategoryName
、SupplierName
UnitPrice
および Discontinued
フィールドをProductName
除くすべてを削除します。 美的なカスタマイズを自由に行うことができます。 フィールドを UnitPrice
通貨値として書式設定し、フィールドの順序を変更し、いくつかのフィールド HeaderText
値の名前を変更することにしました。 また、GridView のスマート タグで [ページングを有効にする] チェック ボックスと [並べ替えを有効にする] チェック ボックスをオンにして、ページングと並べ替えのサポートを含むように GridView を構成します。
Panel、Button、GridView、および ObjectDataSource コントロールを追加し、GridView のフィールドをカスタマイズすると、ページの宣言型マークアップは次のようになります。
<asp:Panel ID="DisplayInterface" runat="server">
<p>
<asp:Button ID="ProcessShipment" runat="server"
Text="Process Product Shipment" />
</p>
<asp:GridView ID="ProductsGrid" runat="server" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsDataSource">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice">
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued">
<ItemStyle HorizontalAlign="Center" />
</asp:CheckBoxField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
</asp:Panel>
Button と GridView のマークアップは、開始タグと終了タグ内に表示されることに注意してください <asp:Panel>
。 これらのコントロールは Panel 内 DisplayInterface
に存在するため、Panel の Visible
プロパティを に false
設定するだけで非表示にすることができます。 手順 3 では、ボタンクリックに応じて Panel の Visible
プロパティをプログラムで変更し、もう一方のインターフェイスを非表示にしながら、1 つのインターフェイスを表示します。
ブラウザーを使用して進行状況を確認してください。 図 5 に示すように、一度に 10 個の製品を一覧表示する GridView の上に [製品出荷の処理] ボタンが表示されます。
図 5: GridView Lists製品とオファーの並べ替えとページング機能 (フルサイズの画像を表示する をクリックします)
手順 2: 挿入インターフェイスの作成
表示インターフェイスが完成したら、挿入インターフェイスを作成する準備ができました。 このチュートリアルでは、1 つの仕入先とカテゴリ値の入力を求める挿入インターフェイスを作成し、ユーザーが最大 5 つの製品名と単価値を入力できるようにします。 このインターフェイスを使用すると、ユーザーは、すべて同じカテゴリとサプライヤーを共有するが、一意の製品名と価格を持つ 1 から 5 つの新製品を追加できます。
まず、ツールボックスからDesignerにパネルをドラッグし、既存DisplayInterface
のパネルの下に配置します。 ID
この新しく追加された Panel の プロパティを にInsertingInterface
設定し、そのプロパティを Visible
にfalse
設定します。 手順 3 で Panel の プロパティを InsertingInterface
に設定するコードをtrue
追加Visible
します。 また、[パネル] と [プロパティ] の Height
値も Width
クリアします。
次に、図 1 に示した挿入インターフェイスを作成する必要があります。 このインターフェイスは、さまざまな HTML 手法を使用して作成できますが、4 列の 7 行テーブルという非常に簡単なものを使用します。
注意
HTML <table>
要素のマークアップを入力する場合は、ソース ビューを使用します。 Visual Studio には、Designerを介して要素を追加<table>
するためのツールが用意されていますが、Designerはマークアップに設定のstyle
割り当てを挿入するのもあまりに進んでいるようです。 マークアップを<table>
作成したら、通常はDesignerに戻って Web コントロールを追加し、そのプロパティを設定します。 事前に決定された列と行を含むテーブルを作成する場合、 Table Web コントロール 内に配置された Web コントロールにはパターンを使用してのみアクセスできるため、Table Web コントロールではなく静的 HTML を FindControl("controlID")
使用することをお勧めします。 ただし、Table Web コントロールはプログラムで構築できるため、動的にサイズ変更されたテーブル (行または列がデータベースまたはユーザー指定の条件に基づくもの) には Table Web コントロールを使用します。
パネルのタグ内に <asp:Panel>
次のマークアップを InsertingInterface
入力します。
<table class="DataWebControlStyle" cellspacing="0">
<tr class="BatchInsertHeaderRow">
<td class="BatchInsertLabel">Supplier:</td>
<td></td>
<td class="BatchInsertLabel">Category:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertAlternatingRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertAlternatingRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertRow">
<td class="BatchInsertLabel">Product:</td>
<td></td>
<td class="BatchInsertLabel">Price:</td>
<td></td>
</tr>
<tr class="BatchInsertFooterRow">
<td colspan="4">
</td>
</tr>
</table>
この <table>
マークアップには、Web コントロールはまだ含まれていません。一時的に追加します。 各<tr>
要素には、特定の CSS クラス設定BatchInsertHeaderRow
が含まれています。仕入先とカテゴリの DropDownList が移動するヘッダー行の場合は 、BatchInsertFooterRow
出荷ボタンとキャンセル ボタンから製品を追加するフッター行の場合は 、製品と単価を含む行の値と TextBox コントロールを交互BatchInsertRow
BatchInsertAlternatingRow
に使用します。 私は、これらのチュートリアルで使用した GridView コントロールと DetailsView コントロールに似た外観を挿入インターフェイスに提供するために、ファイルに Styles.css
対応する CSS クラスを作成しました。 これらの CSS クラスを次に示します。
/*** Styles for ~/BatchData/BatchInsert.aspx tutorial ***/
.BatchInsertLabel
{
font-weight: bold;
text-align: right;
}
.BatchInsertHeaderRow td
{
color: White;
background-color: #900;
padding: 11px;
}
.BatchInsertFooterRow td
{
text-align: center;
padding-top: 5px;
}
.BatchInsertRow
{
}
.BatchInsertAlternatingRow
{
background-color: #fcc;
}
このマークアップを入力して、デザイン ビューに戻ります。 これは<table>
、図 6 に示すように、Designerの 4 列の 7 行のテーブルとして表示されます。
図 6: 挿入インターフェイスは、4 列の Seven-Row テーブルで構成されています (フルサイズの画像を表示する をクリックします)。
これで、Web コントロールを挿入インターフェイスに追加する準備ができました。 ツールボックスから 2 つの DropDownLists を、仕入先用とカテゴリ用のテーブルの適切なセルにドラッグします。
仕入先 DropDownList の ID
プロパティを に Suppliers
設定し、 という名前 SuppliersDataSource
の新しい ObjectDataSource にバインドします。 クラスの GetSuppliers
メソッドからSuppliersBLL
データを取得するように新しい ObjectDataSource を構成し、UPDATE タブのドロップダウン リストを (None) に設定します。 [完了] をクリックしてウィザードを終了します。
図 7: クラスの GetSuppliers
メソッドを使用SuppliersBLL
するように ObjectDataSource を構成する (フルサイズの画像を表示する をクリックします)
DropDownList にSuppliers
データ フィールドをCompanyName
表示させ、その値としてデータ フィールドをListItem
SupplierID
使用します。
図 8: [データ フィールド] CompanyName
と [値として使用 SupplierID
] を表示する (フルサイズの画像を表示する 場合はクリックします)
2 番目の DropDownList Categories
にという名前を付け、それを という名前 CategoriesDataSource
の新しい ObjectDataSource にバインドします。 クラスの GetCategories
メソッドをCategoriesDataSource
使用CategoriesBLL
するように ObjectDataSource を構成します。[UPDATE] タブと [DELETE] タブのドロップダウン リストを [(なし)] に設定し、[完了] をクリックしてウィザードを完了します。 最後に、DropDownList にデータ フィールドを CategoryName
表示させ、値として を CategoryID
使用します。
これら 2 つの DropDownList が追加され、適切に構成された ObjectDataSources にバインドされると、画面は図 9 のようになります。
図 9: ヘッダー行に および Categories
DropDownList が含まれるSuppliers
ようになりました (フルサイズの画像を表示する をクリックします)
ここでは、新しい製品ごとに名前と価格を収集するために TextBoxes を作成する必要があります。 ツールボックスから 5 つの製品名と価格行のそれぞれについて、TextBox コントロールをDesignerにドラッグします。 TextBoxes のID
プロパティをProductName1
、、UnitPrice1
、ProductName2
、UnitPrice2
、ProductName3
UnitPrice3
、、 に設定します。
各単価 TextBoxes の後に CompareValidator を追加し、 プロパティを ControlToValidate
適切な ID
に設定します。 また、 プロパティを Operator
にGreaterThanEqual
ValueToCompare
、0 に、および Type
を に設定しますCurrency
。 これらの設定は、CompareValidator に対して、入力された価格が 0 以上の有効な通貨値であることを確認するように指示します。 プロパティを Text
*に設定し ErrorMessage
、価格を 0 以上にする必要があります。 また、通貨記号は省略してください。
注意
データベース テーブルのフィールドProducts
で値が許可NULL
されていない場合ProductName
でも、挿入インターフェイスには RequiredFieldValidator コントロールは含まれません。 これは、ユーザーが最大 5 つの製品を入力できるようにするためです。 たとえば、ユーザーが最初の 3 行の製品名と単価を指定し、最後の 2 行を空白のままにした場合は、3 つの新しい製品をシステムに追加するだけです。 ただし、 は必須であるためProductName
、単価が入力された場合に対応する製品名の値が提供されるように、プログラムによってチェックする必要があります。 手順 4 では、このチェックに取り組みます。
ユーザーの入力を検証するときに、値に通貨記号が含まれている場合、CompareValidator は無効なデータを報告します。 価格を入力するときに通貨記号を省略するようにユーザーに指示する視覚的な手掛かりとして機能するように、各単価の TextBoxes の前に $ を追加します。
最後に、パネル内に ValidationSummary コントロールを InsertingInterface
追加し、そのプロパティを ShowMessageBox
に true
設定し、その ShowSummary
プロパティを に false
設定します。 これらの設定では、ユーザーが無効な単価値を入力すると、問題のある TextBox コントロールの横にアスタリスクが表示され、ValidationSummary には、前に指定したエラー メッセージを示すクライアント側のメッセージ ボックスが表示されます。
この時点で、画面は図 10 のようになります。
図 10: 挿入インターフェイスに製品名と価格のテキスト ボックスが含まれるようになりました (フルサイズの画像を表示する をクリックします)
次に、[出荷から製品を追加] ボタンと [キャンセル] ボタンをフッター行に追加する必要があります。 ツールボックスから 2 つの Button コントロールを挿入インターフェイスのフッターにドラッグし、Buttons ID
プロパティを に、プロパティを AddProducts
[出荷から製品を追加する] と CancelButton
Text
[キャンセル] にそれぞれ設定します。 さらに、 コントロールの プロパティを CancelButton
に設定しますfalse
。CausesValidation
最後に、2 つのインターフェイスのステータス メッセージを表示する Label Web コントロールを追加する必要があります。 たとえば、ユーザーが製品の新しい出荷を正常に追加した場合は、表示インターフェイスに戻って確認メッセージを表示します。 ただし、ユーザーが新しい製品の価格を提供し、製品名を省略した場合は、 フィールドが必要であるため、警告メッセージを ProductName
表示する必要があります。 このメッセージは両方のインターフェイスに表示する必要があるため、パネルの外側のページの上部に配置します。
[ツールボックス] から [ラベル Web] コントロールをDesignerのページの上部にドラッグします。 プロパティを ID
にStatusLabel
設定し、プロパティをText
クリアし、 プロパティと EnableViewState
プロパティを Visible
にfalse
設定します。 前のチュートリアルで説明したように、 プロパティを EnableViewState
に false
設定すると、Label のプロパティ値をプログラムで変更し、後続のポストバック時に自動的に既定値に戻すことができます。 これにより、後続のポストバックで消える一部のユーザー アクションに応答してステータス メッセージを表示するためのコードが簡略化されます。 最後に、 コントロールの CssClass
プロパティを Warning に設定StatusLabel
します。これは、大きな斜体、太字、赤のフォントでテキストを表示する でStyles.css
定義された CSS クラスの名前です。
図 11 は、ラベルが追加および構成された後の Visual Studio Designerを示しています。
図 11: コントロールを StatusLabel
2 つのパネル コントロールの上に配置します (フルサイズの画像を表示するには、ここをクリックします)
手順 3: 表示インターフェイスと挿入インターフェイスの切り替え
この時点で、表示インターフェイスと挿入インターフェイスのマークアップを完了しましたが、次の 2 つのタスクが残っています。
- ディスプレイと挿入インターフェイスの切り替え
- 出荷の製品をデータベースに追加する
現在、表示インターフェイスは表示されますが、挿入インターフェイスは非表示になっています。 これは、 DisplayInterface
Panel の Visible
プロパティが に true
設定され (既定値) InsertingInterface
、Panel s Visible
プロパティが に false
設定されているためです。 2 つのインターフェイスを切り替えるには、各コントロールの Visible
プロパティ値を切り替える必要があります。
[製品出荷の処理] ボタンがクリックされたときに、表示インターフェイスから挿入インターフェイスに移動します。 したがって、次のコードを含むこの Button s イベントの Click
イベント ハンドラーを作成します。
protected void ProcessShipment_Click(object sender, EventArgs e)
{
DisplayInterface.Visible = false;
InsertingInterface.Visible = true;
}
このコードは、パネルを非表示にし、 DisplayInterface
パネルを InsertingInterface
表示するだけです。
次に、挿入インターフェイスの [出荷から製品を追加] コントロールと [キャンセル] ボタン コントロールのイベント ハンドラーを作成します。 これらのボタンのいずれかがクリックされたら、表示インターフェイスに戻す必要があります。 両方の Button コントロールのイベント ハンドラーを作成 Click
して、 を呼び出 ReturnToDisplayInterface
すようにします。これは、一時的に追加するメソッドです。 パネルを InsertingInterface
非表示にしてパネルを DisplayInterface
表示するだけでなく、 ReturnToDisplayInterface
Web コントロールを編集前の状態に戻す必要があります。 これには、DropDownLists SelectedIndex
プロパティを 0 に設定し、TextBox コントロールのプロパティをクリア Text
する必要があります。
注意
表示インターフェイスに戻る前に、コントロールを編集前の状態に戻さなかった場合に何が起こるかを検討してください。 ユーザーは、[製品出荷の処理] ボタンをクリックし、出荷の製品を入力して、[出荷から製品を追加] をクリックする場合があります。 これにより、製品が追加され、ユーザーが表示インターフェイスに戻ります。 この時点で、ユーザーは別の出荷を追加したい場合があります。 [製品出荷の処理] ボタンをクリックすると、挿入インターフェイスに戻りますが、DropDownList の選択と TextBox の値には以前の値が設定されます。
protected void AddProducts_Click(object sender, EventArgs e)
{
// TODO: Save the products
// Revert to the display interface
ReturnToDisplayInterface();
}
protected void CancelButton_Click(object sender, EventArgs e)
{
// Revert to the display interface
ReturnToDisplayInterface();
}
const int firstControlID = 1;
const int lastControlID = 5;
private void ReturnToDisplayInterface()
{
// Reset the control values in the inserting interface
Suppliers.SelectedIndex = 0;
Categories.SelectedIndex = 0;
for (int i = firstControlID; i <= lastControlID; i++)
{
((TextBox)InsertingInterface.FindControl("ProductName" + i.ToString())).Text =
string.Empty;
((TextBox)InsertingInterface.FindControl("UnitPrice" + i.ToString())).Text =
string.Empty;
}
DisplayInterface.Visible = true;
InsertingInterface.Visible = false;
}
どちらのイベント ハンドラーも Click
単に メソッドを ReturnToDisplayInterface
呼び出しますが、手順 4 の [出荷 Click
から製品を追加] イベント ハンドラーに戻り、製品を保存するコードを追加します。 ReturnToDisplayInterface
は、 および Categories
DropDownLists を最初のオプションに戻Suppliers
すことによって開始されます。 2 つの定数firstControlID
とlastControlID
、挿入インターフェイスで製品名と単価の TextBoxes に名前を付ける際に使用される開始および終了コントロールのインデックス値をマークし、TextBox コントロールのプロパティを空の文字列に戻Text
すループのfor
境界で使用されます。 最後に、挿入インターフェイスが非表示になり、表示インターフェイスが表示されるように、パネル Visible
のプロパティがリセットされます。
ブラウザーでこのページをテストしてください。 最初にページにアクセスすると、図 5 のように表示インターフェイスが表示されます。 [製品出荷の処理] ボタンをクリックします。 ページはポストバックされ、図 12 に示すように挿入インターフェイスが表示されます。 [出荷から製品を追加] または [キャンセル] ボタンをクリックすると、表示インターフェイスに戻ります。
注意
挿入インターフェイスを表示しているときに、単価 TextBoxes で CompareValidators をテストします。 無効な通貨値または値が 0 未満の価格の [出荷から製品を追加] ボタンをクリックすると、クライアント側のメッセージ ボックス警告が表示されます。
図 12: [製品出荷の処理] ボタンをクリックすると、[挿入インターフェイス] が表示されます (フルサイズの画像を表示する場合をクリックします)
手順 4: 製品を追加する
このチュートリアルで残っているのは、製品を [出荷ボタン Click
から製品を追加] イベント ハンドラーのデータベースに保存することです。 これを実現するには、 を ProductsDataTable
作成し、指定された製品名ごとに インスタンスを追加 ProductsRow
します。 これらの ProductsRow
が追加されたら、 を渡すクラス s UpdateWithTransaction
メソッドをProductsBLL
呼び出しますProductsDataTable
。 Transaction チュートリアルの「データベースのUpdateWithTransaction
変更をラップする」チュートリアルで作成された メソッドが、 メソッドに をProductsTableAdapter
UpdateWithTransaction
渡ProductsDataTable
したことを思い出してください。 そこから、ADO.NET トランザクションが開始され、TableAdapter は DataTable に追加ProductsRow
されたそれぞれに対してステートメントをデータベースに発行INSERT
します。 すべての製品がエラーなしで追加されると仮定すると、トランザクションはコミットされ、それ以外の場合はロールバックされます。
[出荷ボタンからの製品の追加] イベント ハンドラーの Click
コードでも、少しエラー チェックを実行する必要があります。 挿入インターフェイスには RequiredFieldValidators が使用されていないので、ユーザーは製品の価格を入力し、その名前を省略できます。 製品名は必須であるため、このような条件が展開される場合は、ユーザーに警告し、挿入を続行する必要はありません。 完全な Click
イベント ハンドラー コードは次のとおりです。
protected void AddProducts_Click(object sender, EventArgs e)
{
// Make sure that the UnitPrice CompareValidators report valid data...
if (!Page.IsValid)
return;
// Add new ProductsRows to a ProductsDataTable...
Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
for (int i = firstControlID; i <= lastControlID; i++)
{
// Read in the values for the product name and unit price
string productName = ((TextBox)InsertingInterface.FindControl
("ProductName" + i.ToString())).Text.Trim();
string unitPrice = ((TextBox)InsertingInterface.FindControl
("UnitPrice" + i.ToString())).Text.Trim();
// Ensure that if unitPrice has a value, so does productName
if (unitPrice.Length > 0 && productName.Length == 0)
{
// Display a warning and exit this event handler
StatusLabel.Text = "If you provide a unit price you must also " +
"include the name of the product.";
StatusLabel.Visible = true;
return;
}
// Only add the product if a product name value is provided
if (productName.Length > 0)
{
// Add a new ProductsRow to the ProductsDataTable
Northwind.ProductsRow newProduct = products.NewProductsRow();
// Assign the values from the web page
newProduct.ProductName = productName;
newProduct.SupplierID = Convert.ToInt32(Suppliers.SelectedValue);
newProduct.CategoryID = Convert.ToInt32(Categories.SelectedValue);
if (unitPrice.Length > 0)
newProduct.UnitPrice = Convert.ToDecimal(unitPrice);
// Add any "default" values
newProduct.Discontinued = false;
newProduct.UnitsOnOrder = 0;
products.AddProductsRow(newProduct);
}
}
// If we reach here, see if there were any products added
if (products.Count > 0)
{
// Add the new products to the database using a transaction
ProductsBLL productsAPI = new ProductsBLL();
productsAPI.UpdateWithTransaction(products);
// Rebind the data to the grid so that the products just added are displayed
ProductsGrid.DataBind();
// Display a confirmation (don't use the Warning CSS class, though)
StatusLabel.CssClass = string.Empty;
StatusLabel.Text = string.Format(
"{0} products from supplier {1} have been added and filed under " +
"category {2}.", products.Count, Suppliers.SelectedItem.Text,
Categories.SelectedItem.Text);
StatusLabel.Visible = true;
// Revert to the display interface
ReturnToDisplayInterface();
}
else
{
// No products supplied!
StatusLabel.Text = "No products were added. Please enter the product " +
"names and unit prices in the textboxes.";
StatusLabel.Visible = true;
}
}
イベント ハンドラーは、プロパティが の値true
を確実にPage.IsValid
返すことによって開始されます。 が返false
された場合は、1 つ以上の CompareValidator が無効なデータを報告していることを意味します。このような場合は、入力した製品を挿入しようとしないか、ユーザーが入力した単価値を s UnitPrice
プロパティにProductsRow
割り当てようとしたときに例外が発生します。
次に、新 ProductsDataTable
しいインスタンスが作成されます (products
)。 for
ループは製品名と単価 TextBoxes を反復処理するために使用され、Text
プロパティはローカル変数 productName
と unitPrice
に読み込まれます。 ユーザーが単価の値を入力したが、対応する製品名の値を入力していない場合は、 StatusLabel
メッセージが表示されます単価を指定する場合は、製品の名前も含める必要があり、イベント ハンドラーが終了します。
製品名が指定されている場合は、 メソッドNewProductsRow
を使用して新しいProductsRow
インスタンスがProductsDataTable
作成されます。 この新しいProductsRow
インスタンスの ProductName
プロパティは現在の製品名 TextBox に設定されSelectedValue
SupplierID
、 プロパティと CategoryID
プロパティは挿入インターフェイスの ヘッダーの DropDownLists のプロパティに割り当てられます。 ユーザーが製品の価格の値を入力した場合、その値はインスタンスの UnitPrice
プロパティにProductsRow
割り当てられます。それ以外の場合、プロパティは未割り当てのままになり、データベース内で NULL
のUnitPrice
値が生成されます。 最後に、 Discontinued
プロパティと UnitsOnOrder
プロパティがそれぞれハードコーディングされた値 false
と 0 に割り当てられます。
プロパティがインスタンスに ProductsRow
割り当てられると、 に追加されます ProductsDataTable
。
ループが完了for
すると、製品が追加されたかどうかをチェックします。 ユーザーは、結局のところ、製品名または価格を入力する前に、出荷から製品を追加するをクリックすることができます。 に ProductsDataTable
少なくとも 1 つの製品がある場合、 ProductsBLL
クラス s UpdateWithTransaction
メソッドが呼び出されます。 次に、新しく追加された製品が表示インターフェイスに ProductsGrid
表示されるように、データは GridView に再バインドされます。 StatusLabel
が更新されて確認メッセージが表示され、 ReturnToDisplayInterface
が呼び出され、挿入インターフェイスが非表示になり、表示インターフェイスが表示されます。
製品が入力されていない場合、挿入インターフェイスは表示されたままですが、メッセージ「製品は追加されませんでした」と表示されます。 テキストボックスに製品名と単価を入力してください。
図 13、14、および 15 は、動作中の挿入インターフェイスと表示インターフェイスを示しています。 図 13 では、ユーザーは対応する製品名なしで単価値を入力しています。 図 14 は、3 つの新しい製品が正常に追加された後の表示インターフェイスを示しています。図 15 は、GridView に新しく追加された 2 つの製品を示しています (3 つ目は前のページにあります)。
図 13: 単価を入力するときに製品名が必要です (フルサイズの画像を表示する をクリックします)
図 14: 3 つの新しい Veggies が仕入先の真弓に追加されました (フルサイズの画像を表示する をクリックします)。
図 15: GridView の最後のページで新しい製品を見つけることができます (フルサイズの画像を表示する をクリックします)。
注意
このチュートリアルで使用するバッチ挿入ロジックは、トランザクションのスコープ内で挿入をラップします。 これを確認するために、意図的にデータベース レベルのエラーが発生します。 たとえば、DropDownList でCategories
選択した値に新しいProductsRow
インスタンスのCategoryID
プロパティを割り当てるのではなく、 のようなi * 5
値に割り当てます。 ループ インデクサーを次 i
に示します。値は 1 ~ 5 です。 したがって、バッチ挿入で 2 つ以上の製品を追加すると、最初の製品は有効なCategoryID
値 (5) になりますが、後続の製品にはCategoryID
テーブル内のCategories
値とCategoryID
一致しない値が含まれます。 その結果、最初 INSERT
のが成功すると、後続のキーは外部キー制約違反で失敗します。 バッチ挿入はアトミックであるため、最初 INSERT
のはロールバックされ、バッチ挿入プロセスが開始される前の状態にデータベースが返されます。
まとめ
このチュートリアルと前の 2 つのチュートリアルでは、データのバッチの更新、削除、挿入を可能にするインターフェイスを作成しました。これらはすべて、トランザクション チュートリアル内の ラッピング データベースの変更 でデータ アクセス層に追加したトランザクション サポートを使用しました。 特定のシナリオでは、このようなバッチ処理ユーザー インターフェイスは、基になるデータの整合性を維持しながら、クリック数、ポストバック、キーボードからマウスへのコンテキスト スイッチの数を減らすことで、エンド ユーザーの効率を大幅に向上させます。
このチュートリアルでは、バッチ データの操作について説明します。 次の一連のチュートリアルでは、TableAdapter のメソッドでのストアド プロシージャの使用、DAL での接続レベルとコマンド レベルの設定の構成、接続文字列の暗号化など、さまざまな高度なデータ アクセス層シナリオについて説明します。
幸せなプログラミング!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、 4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジと協力しています。 Scott は独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・自分自身 ASP.NET 24時間で2.0です。 にアクセスmitchell@4GuysFromRolla.comすることも、ブログを介して アクセスすることもできます。これは でhttp://ScottOnWriting.NET確認できます。
特別な感謝
このチュートリアル シリーズは、多くの役立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、ヒルトン Giesenow と S ren Jacob Lauritsen でした。 今後の MSDN 記事の確認に関心がありますか? その場合は、 に行mitchell@4GuysFromRolla.comをドロップしてください。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示