Share via


一括挿入 (C#)

作成者: Scott Mitchell

PDF のダウンロード

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

はじめに

Batch Updating チュートリアルでは、GridView コントロールをカスタマイズして、複数のレコードが編集可能なインターフェイスを表示する方法について説明しました。 ページにアクセスするユーザーは一連の変更を行い、1 回のボタンクリックでバッチ更新を実行できます。 ユーザーが一度に多くのレコードを一度に更新する場合、このようなインターフェイスは、「 データの挿入、更新、削除の概要 」チュートリアルで最初に確認した既定の行ごとの編集機能と比較して、数え切れないクリックとキーボードからマウスへのコンテキスト スイッチを保存できます。

この概念は、レコードを追加するときにも適用できます。 ここで Northwind Traders では、特定のカテゴリに対して多数の製品を含むサプライヤーから出荷を受け取ることがよくあります。 例えば、東京トレーダーズから6種類の紅茶とコーヒーの商品が出荷される場合があります。 ユーザーが DetailsView コントロールを使用して 6 つの製品を一度に 1 つずつ入力する場合、同じ値の多くを何度も選択する必要があります。同じカテゴリ (飲料)、同じ仕入先 (東京トレーダー)、同じ廃止値 (False)、注文値 (0) の同じ単位を選択する必要があります。 この繰り返しデータ入力には時間がかかるだけでなく、エラーが発生しやすくなります。

少しの作業で、ユーザーが仕入先とカテゴリを 1 回選択し、一連の製品名と単価を入力し、ボタンをクリックして新しい製品をデータベースに追加できるようにするバッチ挿入インターフェイスを作成できます (図 1 を参照)。 各製品が追加されると、その ProductName フィールドと UnitPrice データ フィールドには TextBoxes に入力された値が割り当てられ、その CategoryID 値と SupplierID 値にはフォームの上部にある DropDownLists の値が割り当てられます。 と UnitsOnOrderDiscontinued値はそれぞれ、 と 0 のfalseハードコーディングされた値に設定されます。

バッチ挿入インターフェイス

図 1: バッチ挿入インターフェイス (クリックするとフルサイズの画像が表示されます)

このチュートリアルでは、図 1 に示すバッチ挿入インターフェイスを実装するページを作成します。 前の 2 つのチュートリアルと同様に、トランザクションのスコープ内で挿入をラップして原子性を確保します。 始めましょう。

手順 1: 表示インターフェイスを作成する

このチュートリアルは、表示領域と挿入領域の 2 つの領域に分割された 1 つのページで構成されます。 この手順で作成する表示インターフェイスには、GridView に製品が表示され、[製品出荷の処理] という名前のボタンが含まれています。 このボタンをクリックすると、表示インターフェイスが挿入インターフェイスに置き換えられます(図 1 を参照)。 表示インターフェイスは、[出荷から製品を追加] または [キャンセル] ボタンをクリックした後に戻ります。 手順 2 で挿入インターフェイスを作成します。

一度に 1 つだけ表示される 2 つのインターフェイスを持つページを作成する場合、各インターフェイスは通常、他のコントロールのコンテナーとして機能する Panel Web コントロール内に配置されます。 したがって、このページには、インターフェイスごとに 1 つの 2 つのパネル コントロールがあります。

まず、フォルダー内のページをBatchInsert.aspxBatchData開き、ツールボックスからDesignerにパネルをドラッグします (図 2 を参照)。 Panel s プロパティを IDDisplayInterface設定します。 パネルをDesignerに追加すると、そのHeightプロパティと Width プロパティはそれぞれ 50px と 125px に設定されます。 プロパティ ウィンドウからこれらのプロパティ値をクリアします。

ツールボックスからパネルをDesignerにドラッグする

図 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) に設定します。 [完了] をクリックして、データ ソースの構成ウィザードを完了します。

ProductsBLL クラスの GetProducts メソッドから返されたデータを表示する

図 3: クラスの GetProducts メソッドから返されたデータをProductsBLL表示する (フルサイズの画像を表示する をクリックします)

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

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

ObjectDataSource ウィザードを完了すると、Visual Studio によって、製品データ フィールドに BoundFields と CheckBoxField が追加されます。 、CategoryNameSupplierNameUnitPriceおよび 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 の上に [製品出荷の処理] ボタンが表示されます。

GridView は製品をListsし、並べ替え機能とページング機能を提供します

図 5: GridView Lists製品とオファーの並べ替えとページング機能 (フルサイズの画像を表示する をクリックします)

手順 2: 挿入インターフェイスの作成

表示インターフェイスが完成したら、挿入インターフェイスを作成する準備ができました。 このチュートリアルでは、1 つの仕入先とカテゴリ値の入力を求める挿入インターフェイスを作成し、ユーザーが最大 5 つの製品名と単価値を入力できるようにします。 このインターフェイスを使用すると、ユーザーは、すべて同じカテゴリとサプライヤーを共有するが、一意の製品名と価格を持つ 1 から 5 つの新製品を追加できます。

まず、ツールボックスからDesignerにパネルをドラッグし、既存DisplayInterfaceのパネルの下に配置します。 IDこの新しく追加された Panel の プロパティを にInsertingInterface設定し、そのプロパティを Visiblefalse設定します。 手順 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 コントロールを交互BatchInsertRowBatchInsertAlternatingRowに使用します。 私は、これらのチュートリアルで使用した 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 行のテーブルとして表示されます。

挿入インターフェイスは、4 列の Seven-Row テーブルで構成されます

図 6: 挿入インターフェイスは、4 列の Seven-Row テーブルで構成されています (フルサイズの画像を表示する をクリックします)。

これで、Web コントロールを挿入インターフェイスに追加する準備ができました。 ツールボックスから 2 つの DropDownLists を、仕入先用とカテゴリ用のテーブルの適切なセルにドラッグします。

仕入先 DropDownList の ID プロパティを に Suppliers 設定し、 という名前 SuppliersDataSourceの新しい ObjectDataSource にバインドします。 クラスの GetSuppliers メソッドからSuppliersBLLデータを取得するように新しい ObjectDataSource を構成し、UPDATE タブのドロップダウン リストを (None) に設定します。 [完了] をクリックしてウィザードを終了します。

SuppliersBLL クラスの GetSuppliers メソッドを使用するように ObjectDataSource を構成する

図 7: クラスの GetSuppliers メソッドを使用SuppliersBLLするように ObjectDataSource を構成する (フルサイズの画像を表示する をクリックします)

DropDownList にSuppliersデータ フィールドをCompanyName表示させ、その値としてデータ フィールドをListItemSupplierID使用します。

CompanyName データ フィールドを表示し、値として SupplierID を使用する

図 8: [データ フィールド] CompanyName と [値として使用 SupplierID ] を表示する (フルサイズの画像を表示する 場合はクリックします)

2 番目の DropDownList Categories にという名前を付け、それを という名前 CategoriesDataSourceの新しい ObjectDataSource にバインドします。 クラスの GetCategories メソッドをCategoriesDataSource使用CategoriesBLLするように ObjectDataSource を構成します。[UPDATE] タブと [DELETE] タブのドロップダウン リストを [(なし)] に設定し、[完了] をクリックしてウィザードを完了します。 最後に、DropDownList にデータ フィールドを CategoryName 表示させ、値として を CategoryID 使用します。

これら 2 つの DropDownList が追加され、適切に構成された ObjectDataSources にバインドされると、画面は図 9 のようになります。

ヘッダー行に仕入先とカテゴリの DropDownList が含まれるようになりました

図 9: ヘッダー行に および Categories DropDownList が含まれるSuppliersようになりました (フルサイズの画像を表示する をクリックします)

ここでは、新しい製品ごとに名前と価格を収集するために TextBoxes を作成する必要があります。 ツールボックスから 5 つの製品名と価格行のそれぞれについて、TextBox コントロールをDesignerにドラッグします。 TextBoxes のIDプロパティをProductName1、、UnitPrice1ProductName2UnitPrice2ProductName3UnitPrice3、、 に設定します。

各単価 TextBoxes の後に CompareValidator を追加し、 プロパティを ControlToValidate 適切な IDに設定します。 また、 プロパティを OperatorGreaterThanEqualValueToCompare、0 に、および Type を に設定しますCurrency。 これらの設定は、CompareValidator に対して、入力された価格が 0 以上の有効な通貨値であることを確認するように指示します。 プロパティを Text *に設定し ErrorMessage 、価格を 0 以上にする必要があります。 また、通貨記号は省略してください。

注意

データベース テーブルのフィールドProductsで値が許可NULLされていない場合ProductNameでも、挿入インターフェイスには RequiredFieldValidator コントロールは含まれません。 これは、ユーザーが最大 5 つの製品を入力できるようにするためです。 たとえば、ユーザーが最初の 3 行の製品名と単価を指定し、最後の 2 行を空白のままにした場合は、3 つの新しい製品をシステムに追加するだけです。 ただし、 は必須であるためProductName、単価が入力された場合に対応する製品名の値が提供されるように、プログラムによってチェックする必要があります。 手順 4 では、このチェックに取り組みます。

ユーザーの入力を検証するときに、値に通貨記号が含まれている場合、CompareValidator は無効なデータを報告します。 価格を入力するときに通貨記号を省略するようにユーザーに指示する視覚的な手掛かりとして機能するように、各単価の TextBoxes の前に $ を追加します。

最後に、パネル内に ValidationSummary コントロールを InsertingInterface 追加し、そのプロパティを ShowMessageBoxtrue 設定し、その ShowSummary プロパティを に false設定します。 これらの設定では、ユーザーが無効な単価値を入力すると、問題のある TextBox コントロールの横にアスタリスクが表示され、ValidationSummary には、前に指定したエラー メッセージを示すクライアント側のメッセージ ボックスが表示されます。

この時点で、画面は図 10 のようになります。

挿入インターフェイスに、製品名と価格のテキスト ボックスが含まれるようになりました

図 10: 挿入インターフェイスに製品名と価格のテキスト ボックスが含まれるようになりました (フルサイズの画像を表示する をクリックします)

次に、[出荷から製品を追加] ボタンと [キャンセル] ボタンをフッター行に追加する必要があります。 ツールボックスから 2 つの Button コントロールを挿入インターフェイスのフッターにドラッグし、Buttons ID プロパティを に、プロパティを AddProducts [出荷から製品を追加する] と CancelButtonText [キャンセル] にそれぞれ設定します。 さらに、 コントロールの プロパティを CancelButton に設定しますfalseCausesValidation

最後に、2 つのインターフェイスのステータス メッセージを表示する Label Web コントロールを追加する必要があります。 たとえば、ユーザーが製品の新しい出荷を正常に追加した場合は、表示インターフェイスに戻って確認メッセージを表示します。 ただし、ユーザーが新しい製品の価格を提供し、製品名を省略した場合は、 フィールドが必要であるため、警告メッセージを ProductName 表示する必要があります。 このメッセージは両方のインターフェイスに表示する必要があるため、パネルの外側のページの上部に配置します。

[ツールボックス] から [ラベル Web] コントロールをDesignerのページの上部にドラッグします。 プロパティを IDStatusLabel設定し、プロパティをTextクリアし、 プロパティと EnableViewState プロパティを Visiblefalse設定します。 前のチュートリアルで説明したように、 プロパティを EnableViewStatefalse 設定すると、Label のプロパティ値をプログラムで変更し、後続のポストバック時に自動的に既定値に戻すことができます。 これにより、後続のポストバックで消える一部のユーザー アクションに応答してステータス メッセージを表示するためのコードが簡略化されます。 最後に、 コントロールの CssClass プロパティを Warning に設定StatusLabelします。これは、大きな斜体、太字、赤のフォントでテキストを表示する でStyles.css定義された CSS クラスの名前です。

図 11 は、ラベルが追加および構成された後の Visual Studio Designerを示しています。

2 つのパネル コントロールの上に StatusLabel コントロールを配置する

図 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 つの定数firstControlIDlastControlID、挿入インターフェイスで製品名と単価の TextBoxes に名前を付ける際に使用される開始および終了コントロールのインデックス値をマークし、TextBox コントロールのプロパティを空の文字列に戻Textすループのfor境界で使用されます。 最後に、挿入インターフェイスが非表示になり、表示インターフェイスが表示されるように、パネル Visible のプロパティがリセットされます。

ブラウザーでこのページをテストしてください。 最初にページにアクセスすると、図 5 のように表示インターフェイスが表示されます。 [製品出荷の処理] ボタンをクリックします。 ページはポストバックされ、図 12 に示すように挿入インターフェイスが表示されます。 [出荷から製品を追加] または [キャンセル] ボタンをクリックすると、表示インターフェイスに戻ります。

注意

挿入インターフェイスを表示しているときに、単価 TextBoxes で CompareValidators をテストします。 無効な通貨値または値が 0 未満の価格の [出荷から製品を追加] ボタンをクリックすると、クライアント側のメッセージ ボックス警告が表示されます。

製品出荷処理ボタンをクリックすると、挿入インタフェースが表示されます。

図 12: [製品出荷の処理] ボタンをクリックすると、[挿入インターフェイス] が表示されます (フルサイズの画像を表示する場合をクリックします)

手順 4: 製品を追加する

このチュートリアルで残っているのは、製品を [出荷ボタン Click から製品を追加] イベント ハンドラーのデータベースに保存することです。 これを実現するには、 を ProductsDataTable 作成し、指定された製品名ごとに インスタンスを追加 ProductsRow します。 これらの ProductsRow が追加されたら、 を渡すクラス s UpdateWithTransaction メソッドをProductsBLL呼び出しますProductsDataTable。 Transaction チュートリアルの「データベースUpdateWithTransaction変更をラップする」チュートリアルで作成された メソッドが、 メソッドに をProductsTableAdapterUpdateWithTransactionProductsDataTableしたことを思い出してください。 そこから、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プロパティはローカル変数 productNameunitPriceに読み込まれます。 ユーザーが単価の値を入力したが、対応する製品名の値を入力していない場合は、 StatusLabel メッセージが表示されます単価を指定する場合は、製品の名前も含める必要があり、イベント ハンドラーが終了します。

製品名が指定されている場合は、 メソッドNewProductsRowを使用して新しいProductsRowインスタンスがProductsDataTable作成されます。 この新しいProductsRowインスタンスの ProductName プロパティは現在の製品名 TextBox に設定されSelectedValueSupplierID、 プロパティと CategoryID プロパティは挿入インターフェイスの ヘッダーの DropDownLists のプロパティに割り当てられます。 ユーザーが製品の価格の値を入力した場合、その値はインスタンスの UnitPrice プロパティにProductsRow割り当てられます。それ以外の場合、プロパティは未割り当てのままになり、データベース内で NULLUnitPrice値が生成されます。 最後に、 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: 単価を入力するときに製品名が必要です (フルサイズの画像を表示する をクリックします)

サプライヤー・メイミ社に3つの新しい野菜が追加されました

図 14: 3 つの新しい Veggies が仕入先の真弓に追加されました (フルサイズの画像を表示する をクリックします)。

新しい製品は、GridView の最後のページにあります

図 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をドロップしてください。