挿入、更新、削除に関連付けられているイベントを調べる (VB)

作成者: Scott Mitchell

PDF のダウンロード

このチュートリアルでは、ASP.NET データ Web コントロールの挿入、更新、または削除操作の前後、および操作中に発生するイベントの使用について説明します。 また、製品フィールドのサブセットの更新のみを行うように編集インターフェイスをカスタマイズする方法についても説明します。

はじめに

GridView、DetailsView、または FormView コントロールの組み込みの挿入、編集、または削除機能を使用する場合、エンド ユーザーが新しいレコードの追加または既存のレコードの更新または削除のプロセスを完了すると、さまざまな手順が発生します。 前のチュートリアルで説明したように、GridView で行を編集すると、[編集] ボタンが [更新] ボタンと [キャンセル] ボタンに置き換わり、BoundField が TextBox に変わります。 エンド ユーザーがデータを更新し、[更新] をクリックすると、ポストバック時に次の手順が実行されます。

  1. GridView は ObjectDataSource の UpdateParameters に、編集されたレコードの一意の識別フィールド (DataKeyNames プロパティを使用) とユーザーが入力した値を設定します
  2. GridView は ObjectDataSource の Update() メソッドを呼び出し、基になるオブジェクト (前のチュートリアルの ProductsDAL.UpdateProduct) の適切なメソッドを呼び出します
  3. 更新された変更を含む基になるデータは、GridView に再バインドされます

この一連の手順の間に多数のイベントが発生し、必要に応じてイベント ハンドラーを作成してカスタム ロジックを追加できます。 たとえば、手順 1 より前では、GridView の RowUpdating イベントが発生します。 検証エラーが発生した場合は、この時点で更新要求を取り消すことができます。 Update() メソッドが呼び出されると、ObjectDataSource の Updating イベントが発生し、UpdateParameters のいずれかの値を追加またはカスタマイズする機会が提供されます。 ObjectDataSource の基になるオブジェクトのメソッド実行が完了すると、ObjectDataSource の Updated イベントが発生します。 Updated イベントのイベント ハンドラーは、影響を受けた行の数や例外が発生したかどうかなど、更新操作に関する詳細を調べることができます。 最後に、手順 2 の後に GridView の RowUpdated イベントが発生します。このイベントのイベント ハンドラーは、先ほど実行した更新操作に関する追加情報を調べることができます。

図 1 は、GridView を更新するときのこの一連のイベントと手順を示しています。 図 1 のイベント パターンは、GridView での更新に固有のものではありません。 GridView、DetailsView、または FormView からデータを挿入、更新、または削除すると、データ Web コントロールと ObjectDataSource の両方に対して、同じ一連の事前および事後レベルのイベントが生成されます。

GridView でデータを更新するときに発生する一連の事前イベントと事後イベント

図 1: GridView でデータを更新するときに発生する一連の事前および事後イベント (クリックするとフルサイズの画像が表示されます)

このチュートリアルでは、これらのイベントを使用した、ASP.NET データ Web コントロールの組み込みの挿入、更新、および削除機能の拡張について説明します。 また、製品フィールドのサブセットの更新のみを行うように編集インターフェイスをカスタマイズする方法についても説明します。

手順 1: 製品の ProductName および UnitPrice フィールドを更新する

前のチュートリアルの編集インターフェイスでは、読み取り専用ではない "すべての" 製品フィールドを含める必要がありました。 データを更新するときに GridView からフィールドを削除する場合 ( QuantityPerUnit など)、データ Web コントロールは ObjectDataSource の QuantityPerUnit UpdateParameters 値を設定しません。 この場合、ObjectDataSource は UpdateProduct ビジネス ロジック レイヤー (BLL) メソッドに Nothing の値を渡します。これにより、編集されたデータベース レコードの QuantityPerUnit 列が NULL 値に変更されます。 同様に、編集インターフェイスから必須フィールド (ProductName など) が削除された場合、"列 'ProductName' に nulls を使用することはできません" 例外で更新が失敗します。 この動作の理由は、ObjectDataSource が ProductsBLL クラスの UpdateProduct メソッドを呼び出すように構成されており、各製品フィールドの入力パラメーターが必要だったためです。 そのため、ObjectDataSource の UpdateParameters コレクションには、このメソッドの各入力パラメーターのパラメーターが含まれていました。

エンド ユーザーにフィールドのサブセットの更新のみを許可するデータ Web コントロールを提供する場合は、ObjectDataSource の Updating イベント ハンドラーで UpdateParameters の欠損値をプログラムによって設定するか、フィールドのサブセットのみを受け取る BLL メソッドを作成して呼び出す必要があります。 この後者のアプローチを見てみましょう。

具体的には、編集可能な GridView の ProductName および UnitPrice フィールドだけを表示するページを作成しましょう。 この GridView の編集インターフェイスでは、ProductNameUnitPrice の 2 つの表示フィールドの更新のみがユーザーに許可されます。 この編集インターフェイスでは製品のフィールドのサブセットのみが表示されるため、既存の BLL の UpdateProduct メソッドを使用し、不足している製品フィールド値が Updating イベント ハンドラーでプログラムによって設定される ObjectDataSource を作成するか、GridView で定義されているフィールドのサブセットのみを受け入れる新しい BLL メソッドを作成する必要があります。 このチュートリアルでは後者のオプションを使用し、3 つの入力パラメーター productNameunitPriceproductID のみを受け取る UpdateProduct メソッドのオーバーロードを作成します。

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, False)> _
    Public Function UpdateProduct(productName As String, _
        unitPrice As Nullable(Of Decimal), productID As Integer) _
        As Boolean

    Dim products As Northwind.ProductsDataTable = _
        Adapter.GetProductByProductID(productID)

    If products.Count = 0 Then
        Return False
    End If

    Dim product As Northwind.ProductsRow = products(0)

    product.ProductName = productName
    If Not unitPrice.HasValue Then
        product.SetUnitPriceNull()
    Else
        product.UnitPrice = unitPrice.Value
    End If

    Dim rowsAffected As Integer = Adapter.Update(product)

    Return rowsAffected = 1
End Function

元の UpdateProduct メソッドと同様に、このオーバーロードは、指定した ProductID を持つ製品がデータベース内に存在するかどうかを確認することから始めます。 ない場合は False が返されます。これは、製品情報の更新要求が失敗したことを示します。 それ以外の場合は、既存の製品レコードの ProductName および UnitPrice フィールドを適宜更新し、TableAdapter の Update() メソッドを呼び出し、ProductsRow インスタンスを渡して更新をコミットします。

ProductsBLL クラスへの追加によって、簡略化された GridView インターフェイスを作成する準備ができました。 EditInsertDelete フォルダーの DataModificationEvents.aspx を開き、ページに GridView を追加します。 新しい ObjectDataSource を作成し、ProductsBLL クラスで、その Select() メソッドを GetProducts にマッピングし、その Update() メソッドを、productNameunitPriceproductID 入力パラメーターのみを受け取る UpdateProduct オーバーロードにマッピングして使用されるように構成します。 図 2 は、ObjectDataSource の Update() メソッドを ProductsBLL クラスの新しい UpdateProduct メソッド オーバーロードにマッピングするときのデータ ソースの作成ウィザードを示しています。

ObjectDataSource の Update() メソッドを新しい UpdateProduct オーバーロードにマップする

図 2: ObjectDataSource の Update() メソッドを新しい UpdateProduct オーバーロードにマップします (クリックするとフルサイズの画像が表示されます)

この例では、最初はデータの編集機能のみが必要で、レコードの挿入や削除は必要ないため、[INSERT] タブと [DELETE] タブに移動し、ドロップダウン リストから [(None)] を選択して、ObjectDataSource の Insert() および Delete() メソッドを ProductsBLL クラスのメソッドにマップしないことを明示的に示します。

INSERT タブと DELETE タブのドロップダウン リストから [(なし)] を選択します

図 3: [INSERT] タブと [DELETE] タブのドロップダウン リストから [(None)] を選択します (クリックするとフルサイズの画像が表示されます)

このウィザードを完了したら、GridView のスマート タグから [編集チェックを有効にする] チェック ボックスをオンにします。

データ ソースの作成ウィザードが完了し、GridView にバインドされたので、Visual Studio によって両方のコントロールの宣言構文が作成されました。 次に示すように、ObjectDataSource の宣言型マークアップを調べるには、ソース ビューに移動します。

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
    TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

ObjectDataSource の Insert() および Delete() メソッドのマッピングがないため、InsertParameters または DeleteParameters セクションはありません。 さらに、Update() メソッドは 3 つの入力パラメーターのみを受け取る UpdateProduct メソッド オーバーロードにマップされるため、UpdateParameters セクションには 3 つの Parameter インスタンスしかありません。

ObjectDataSource の OldValuesParameterFormatString プロパティが original_{0} に設定されていることに注意してください。 このプロパティは、データ ソースの構成ウィザードを使用すると、Visual Studio によって自動的に設定されます。 ただし、BLL メソッドでは元の ProductID 値が渡されることを想定していないため、ObjectDataSource の宣言構文からこのプロパティの割り当てを完全に削除してください。

Note

デザイン ビューのプロパティ ウィンドウから OldValuesParameterFormatString プロパティ値をクリアすると、プロパティは宣言構文にはありますが、空の文字列に設定されます。 宣言構文からプロパティを完全に削除するか、プロパティ ウィンドウから値を既定値の {0} に設定します。

ObjectDataSource には、製品の名前、価格、ID の UpdateParameters しかありませんが、Visual Studio では、製品の各フィールドに対して GridView で BoundField または CheckBoxField が追加されています。

GridView には、製品の各フィールドの BoundField または CheckBoxField が含まれています

図 4: GridView には製品の各フィールドに対して BoundField または CheckBoxField が含まれています (クリックするとフルサイズの画像が表示されます)

エンド ユーザーが製品を編集し、[更新] ボタンをクリックすると、読み取り専用ではないフィールドが GridView によって列挙されます。 次に、ObjectDataSource の UpdateParameters コレクション内の対応するパラメーターの値が、ユーザーが入力した値に設定されます。 対応するパラメーターがない場合、GridView によってコレクションに追加されます。 そのため、GridView で製品のすべてのフィールドに対して BoundField と CheckBoxField が含まれている場合、ObjectDataSource は、ObjectDataSource の宣言型マークアップで 3 つの入力パラメーターのみが指定されるという事実にもかかわらず、これらのパラメーターをすべて受け取る UpdateProduct オーバーロードを呼び出します (図 5 を参照)。 同様に、GridView に、UpdateProduct オーバーロードの入力パラメーターに対応しない読み取り専用ではない製品フィールドの組み合わせがある場合、更新しようとすると例外が発生します。

GridView は ObjectDataSource の UpdateParameters コレクションにパラメーターを追加します

図 5: GridView は ObjectDataSource の UpdateParameters コレクションにパラメーターを追加します (クリックするとフルサイズの画像が表示されます)

ObjectDataSource が、製品の名前、価格、ID のみを受け取る UpdateProduct オーバーロードを呼び出すようにするには、ProductName および UnitPrice の編集可能なフィールドのみを持つよう GridView を制限する必要があります。 これを実行するには、他の BoundField と CheckBoxField を削除します。これには、それらの他のフィールドの ReadOnly プロパティを True に設定するか、2 つの何らかの組み合わせを設定します。 このチュートリアルでは、ProductName および UnitPrice BoundField を除くすべての GridView フィールドを削除します。その後、GridView の宣言型マークアップは次のようになります。

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="ProductName"
          HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
          SortExpression="UnitPrice" />
    </Columns>
</asp:GridView>

UpdateProduct オーバーロードでは 3 つの入力パラメーターを受け取りますが、GridView には BoundField が 2 つだけあります。 これは、productID 入力パラメーターが主キー値であり、編集された行の DataKeyNames プロパティの値を介して渡されるためです。

GridView と UpdateProduct オーバーロードにより、ユーザーは他の製品フィールドを失うことなく、製品の名前と価格のみを編集できます。

インターフェイスでは、製品の名前と価格のみを編集できます

図 6: インターフェイスでは、製品の名前と価格のみを編集できます (クリックするとフルサイズの画像が表示されます)

Note

前のチュートリアルで説明したように、GridView のビュー状態を有効にすることが非常に重要です (既定の動作)。 GridView の EnableViewState プロパティを false に設定すると、同時実行ユーザーが意図せずにレコードを削除または編集するリスクが発生します。

UnitPrice の書式設定の改善

図 6 に示す GridView の例は機能しますが、UnitPrice フィールドの書式設定がまったく行われず、通貨記号なしの小数点以下 4 桁の価格表示になります。 編集できない行に通貨書式を適用するには、UnitPrice BoundField の DataFormatString プロパティを {0:c} に、その HtmlEncode プロパティを False に設定します。

それに応じて、UnitPrice の DataFormatString プロパティと HtmlEncode プロパティを設定します

図 7: UnitPriceDataFormatString および HtmlEncode プロパティを適宜設定します (クリックするとフルサイズの画像が表示されます)

この変更により、編集できない行は価格が通貨として書式設定されます。ただし、編集された行には、通貨記号なしの小数点以下 4 桁の値が表示されます。

編集できない行が通貨値として書式設定されるようになりました

図 8: 編集できない行が通貨値として書式設定されました (クリックするとフルサイズの画像が表示されます)

DataFormatString プロパティで指定された書式設定命令は、BoundField の ApplyFormatInEditMode プロパティを True に設定することで (既定値は False)、編集インターフェイスに適用できます。 このプロパティを True に設定します。

UnitPrice BoundField の ApplyFormatInEditMode プロパティを True に設定します。

図 9: UnitPrice BoundField の ApplyFormatInEditMode プロパティを True に設定します (クリックするとフルサイズの画像が表示されます)

この変更により、編集された行に表示される UnitPrice の値も通貨として書式設定されます。

編集された行の UnitPrice 値が通貨として書式設定されていることを示す GridView のスクリーンショット。

図 10: 編集された行の UnitPrice 値が通貨として書式設定されるようになりました (クリックするとフルサイズの画像が表示されます)

ただし、$19.00 など、テキスト ボックスの通貨記号を使用して製品を更新すると、FormatException がスローされます。 GridView がユーザー指定の値を ObjectDataSource のUpdateParameters コレクションに割り当てようとすると、UnitPrice 文字列 "$19.00" をパラメーターで必要な Decimal に変換することができません (図 11 を参照)。 これを解決するために、GridView の RowUpdating イベントのイベント ハンドラーを作成し、ユーザーが指定した UnitPrice を通貨書式の Decimal として解析させます。

GridView の RowUpdating イベントは、2 番目のパラメーターとして型 GridViewUpdateEventArgs のオブジェクトを受け取ります。これには、ObjectDataSource の UpdateParameters コレクションに割り当てられる準備ができているユーザー指定の値を保持するプロパティの 1 つとして NewValues ディクショナリが含まれます。 RowUpdating イベント ハンドラー内の次のコード行で通貨書式を使用して解析された 10 進値を使用して NewValues コレクション内の既存の UnitPrice 値を上書きできます。

Protected Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) _
    Handles GridView1.RowUpdating
    If e.NewValues("UnitPrice") IsNot Nothing Then
        e.NewValues("UnitPrice") = _
            Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
                System.Globalization.NumberStyles.Currency)
    End If
End Sub

ユーザーが UnitPrice 値 ("$19.00" など) を指定した場合、この値は Decimal.Parse によって計算された 10 進値で上書きされ、値が通貨として解析されます。 これにより、通貨記号、コンマ、小数点などの場合に小数点が正しく解析され、System.Globalization 名前空間の NumberStyles 列挙型が使用されます。

図 11 は、ユーザー指定の UnitPrice の通貨記号によって発生する問題と、GridView の RowUpdating イベント ハンドラーを使用してこのような入力を正しく解析する方法の両方を示しています。

ObjectDataSource が UnitPrice フィールドを処理する方法と、GridView の RowUpdate イベント ハンドラーが文字列を 10 進数に変換する方法を示す図。

図 11: 編集された行の UnitPrice 値が通貨として書式設定されるようになりました (クリックするとフルサイズの画像が表示されます)

手順 2: NULL UnitPrices を禁止する

Products テーブルのUnitPrice列のNULL値を許可するようにデータベースが構成されていますが、この特定のページにアクセスするユーザーがNULL UnitPrice値を指定できないようにすることができます。 つまり、ユーザーが製品行の編集時に UnitPrice 値の入力に失敗した場合、結果をデータベースに保存するのではなく、このページを通じて、編集された製品に価格が指定されている必要があることをユーザーに通知するメッセージを表示します。

GridView の RowUpdating イベント ハンドラーに渡される GridViewUpdateEventArgs オブジェクトには、True に設定した場合、更新プロセスを終了する Cancel プロパティが含まれています。 RowUpdating イベント ハンドラーを拡張して e.CancelTrue に設定し、NewValues コレクション内の UnitPrice 値が Nothing の値である理由を説明するメッセージを表示してみましょう。

まず、Label Web コントロールを MustProvideUnitPriceMessage という名前の付いたページに追加します。 ユーザーが製品の更新時に UnitPrice 値の指定に失敗した場合、この Label コントロールが表示されます。 Label の Text プロパティを "You must provide a price for the product." (製品の価格を指定する必要があります) に設定します。また、次の定義を持つ Warning という名前の Styles.css に新しい CSS クラスを作成しました。

.Warning
{
    color: Red;
    font-style: italic;
    font-weight: bold;
    font-size: x-large;
}

最後に、Label の CssClass プロパティを Warning に設定します。 この時点で、図 12 に示すように、デザイナーは GridView の上に赤、太字、斜体、特に大きなフォント サイズで警告メッセージを表示する必要があります。

GridView の上にラベルが追加されました

図 12: GridView の上に Label が追加されました (クリックするとフルサイズの画像が表示されます)

既定では、この Label は非表示になっているため、Page_Load イベント ハンドラーで Visible プロパティを False に設定します。

Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    MustProvideUnitPriceMessage.Visible = False
End Sub

ユーザーが UnitPrice を指定せずに製品を更新しようとすると、更新が取り消されて警告ラベルが表示されることがあります。 GridView の RowUpdating イベント ハンドラーを次のように拡張します。

Protected Sub GridView1_RowUpdating(sender As Object, e As GridViewUpdateEventArgs) _
    Handles GridView1.RowUpdating

    If e.NewValues("UnitPrice") IsNot Nothing Then
        e.NewValues("UnitPrice") = _
            Decimal.Parse(e.NewValues("UnitPrice").ToString(), _
                System.Globalization.NumberStyles.Currency)
    Else
        MustProvideUnitPriceMessage.Visible = True

        e.Cancel = True
    End If
End Sub

ユーザーが価格を指定せずに製品を保存しようとすると、更新は取り消され、役に立つメッセージが表示されます。 データベース (およびビジネス ロジック) では NULL UnitPrice が可能ですが、この特定の ASP.NET ページでは使用できません。

ユーザーが UnitPrice を空白のままにできない

図 13: ユーザーは UnitPrice を空白のままにすることはできません (クリックするとフルサイズの画像が表示されます)

ここまでは、GridView の RowUpdating イベントを使用して、ObjectDataSource の UpdateParameters コレクションに割り当てられているパラメーター値をプログラムによって変更する方法と、更新プロセスを完全に取り消す方法について説明しました。 これらの概念は DetailsView および FormView コントロールに引き継がれ、挿入と削除にも適用されます。

これらのタスクは、ObjectDataSource レベルで、そのInsertingUpdatingDeleting イベントのイベント ハンドラーを使用して実行することもできます。 これらのイベントは、基になるオブジェクトの関連付けられたメソッドが呼び出される前に発生し、入力パラメーター コレクションを変更したり、操作を完全に取り消したりする最後の機会を提供します。 これら 3 つのイベントのイベント ハンドラーには、対象となる次の 2 つのプロパティを持つ ObjectDataSourceMethodEventArgs 型のオブジェクトが渡されます。

  • CancelTrue に設定すると、実行中の操作が取り消されます。
  • InputParametersInsertParametersUpdateParameters、または DeleteParameters のコレクション (イベント ハンドラーが Inserting か、Updating か、または Deleting イベント用かどうかに応じる)

ObjectDataSource レベルでパラメーター値を操作する方法を説明するために、ユーザーが新しい製品を追加できるようにする DetailsView をページに含めましょう。 この DetailsView は、データベースに新しい製品をすばやく追加するためのインターフェイスを提供するために使用されます。 新しい製品を追加するときに一貫したユーザー インターフェイスを維持するために、ユーザーが ProductName および UnitPrice フィールドの値のみを入力できるようにしましょう。 既定では、DetailsView の挿入インターフェイスで指定されていない値は、データベース値に NULL が設定されます。 ただし、ObjectDataSource の Inserting イベントを使用して異なる既定値を挿入することもできます。これについては、後で説明します。

手順 3: 新しい製品を追加するためのインターフェイスを提供する

ツールボックスから GridView の上にあるデザイナーに DetailsView をドラッグし、その Height および Width プロパティをクリアして、ページに既に存在する ObjectDataSource にバインドします。 これにより、製品の各フィールドの BoundField または CheckBoxField が追加されます。 この DetailsView を使用して新しい製品を追加するため、スマート タグから [挿入を有効にする] オプションをオンにする必要があります。ただし、ObjectDataSource の Insert() メソッドは ProductsBLL クラスのメソッドにマップされていないため、このようなオプションはありません (データ ソースを構成するときに、このマッピングを [(None)] に設定したことを思い出してください。図 3 を参照)。

ObjectDataSource を構成するには、スマート タグから [データ ソースの構成] リンクを選択し、ウィザードを起動します。 最初の画面では、ObjectDataSource がバインドされている基になるオブジェクトを変更できます。ProductsBLL に設定したままにしておきます。 次の画面では、ObjectDataSource のメソッドから基になるオブジェクトへのマッピングが一覧表示されます。 Insert() および Delete() メソッドをどのメソッドにもマップしないことを明示的に示しましたが、[INSERT] タブと [DELETE] タブに移動すると、マッピングが存在することがわかります。 これは、ProductsBLLAddProductDeleteProduct メソッドが DataObjectMethodAttribute 属性を使用して、それらがそれぞれ Insert()Delete() の既定のメソッドであることを示しているためです。 そのため、他の値が明示的に指定されていない限り、ウィザードを実行するたびに ObjectDataSource ウィザードによってこれらが選択されます。

Insert() メソッドは AddProduct メソッドを指したままにしますが、[DELETE] タブのドロップダウン リストは [(None)] に設定します。

INSERT タブのドロップダウン リストを AddProduct メソッドに設定する

図 14: INSERT タブのドロップダウン リストを AddProduct メソッドに設定します (クリックするとフルサイズの画像が表示されます)

DELETE タブのドロップダウン リストを (なし) に設定する

図 15: [DELETE] タブでドロップダウン リストを [(None)] に設定します (クリックするとフルサイズの画像が表示されます)

これらの変更を行うと、次に示すように、ObjectDataSource の宣言構文が展開され、InsertParameters コレクションが含められます。

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    SelectMethod="GetProducts" TypeName="ProductsBLL"
    UpdateMethod="UpdateProduct" OnUpdating="ObjectDataSource1_Updating"
    InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
    <InsertParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
    </InsertParameters>
</asp:ObjectDataSource>

ウィザードを再実行することで、OldValuesParameterFormatString プロパティが追加されました。 このプロパティを既定値 ({0}) に設定するか、宣言構文から完全に削除して、このプロパティをクリアします。

挿入機能を提供する ObjectDataSource では、DetailsView のスマート タグに [挿入を有効にする] チェックボックスが含まれるようになりました。デザイナーに戻り、このオプションをオンにします。 次に、DetailsView が BoundField - ProductNameUnitPrice - CommandField の 2 つだけになるようにします。 この時点で、DetailsView の宣言構文は次のようになります。

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Fields>
        <asp:BoundField DataField="ProductName"
          HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
          SortExpression="UnitPrice" />
        <asp:CommandField ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

図 16 は、この時点でブラウザーで表示された場合のこのページを示しています。 ご覧のように、DetailsView には最初の製品 (Chai) の名前と価格が一覧表示されます。 ただし、ユーザーが新しい製品をすばやくデータベースに追加するための手段を提供する挿入インターフェイスが必要です。

DetailsView は現在、読み取り専用モードでレンダリングされています

図 16: DetailsView は現在読み取り専用モードでレンダリングされています (クリックするとフルサイズの画像が表示されます)

DetailsView を挿入モードで表示するには、DefaultMode プロパティを Inserting に設定する必要があります。 これにより、最初にアクセスしたときに DetailsView が挿入モードでレンダリングされ、新しいレコードを挿入した後もそこに保持されます。 図 17 に示すように、このような DetailsView には、新しいレコードを追加するためのクイック インターフェイスが用意されています。

DetailsView は、新しい製品をすばやく追加するためのインターフェイスを提供します

図 17: DetailsView によって、新しい製品をすばやく追加するためのインターフェイスが提供されます (クリックするとフルサイズの画像が表示されます)

ユーザーが製品名と価格 (図 17 のように "Acme Water" や 1.99 など) を入力して [挿入] をクリックすると、ポストバックが続き、挿入ワークフローが開始され、新しい製品レコードがデータベースに追加されます。 DetailsView には挿入インターフェイスが維持され、図 18 に示すように、新しい製品を含めるために GridView がデータ ソースに自動的に再バインドされます。

製品

図 18: 製品 "Acme Water" がデータベースに追加されました

図 18 の GridView には表示されませんが、DetailsView インターフェイスには製品フィールドがなく、CategoryIDSupplierIDQuantityPerUnit などにはデータベース値 NULL が割り当てられています。 これを確認するには、次の手順を実行します。

  1. Visual Studio のサーバー エクスプローラーに移動する
  2. NORTHWND.MDF データベース ノードを展開する
  3. Products データベース テーブル ノードを右クリックする
  4. [テーブル データの表示] を選択する

これにより、Products テーブル内のすべてのレコードが一覧表示されます。 図 19 に示すように、ProductIDProductNameUnitPrice 以外の新しい製品のすべての列に、NULL 値が設定されます。

DetailsView に指定されていない製品フィールドには NULL 値が割り当てられます

図 19: DetailsView で指定されていない製品フィールドに NULL 値が割り当てられています (クリックするとフルサイズの画像が表示されます)

NULL が最適な既定のオプションではない、またはデータベース列自体で NULL が許可されていないため、これらの列の 1 つ以上の値に NULL 以外の既定値を指定することをお勧めします。 これを実現するために、DetailsView の InputParameters のコレクションのパラメーターの値をプログラムによって設定できます。 この割り当ては、DetailsView の ItemInserting イベントまたは ObjectDataSource の Inserting イベントのイベント ハンドラーのいずれかで実行できます。 データ Web コントロール レベルでの事前および事後レベルのイベントの使用を既に確認したので、今度は ObjectDataSource のイベントを使用して調べてみましょう。

手順 4: 値を CategoryID および SupplierID パラメーターに割り当てる

このチュートリアルで、このインターフェイスを介して新しい製品を追加するときに、アプリケーションに CategoryIDSupplierID 値の 1 を割り当てる必要があるとします。 前に説明したように、ObjectDataSource には、データ変更プロセス中に発生する事前および事後レベルのイベントのペアがあります。 その Insert() メソッドが呼び出されると、ObjectDataSource は最初にその Inserting イベントを発生させ、次にその Insert() メソッドのマップ先メソッドを呼び出し、最後に Inserted イベントを発生させます。 Inserting イベント ハンドラーは、入力パラメーターを調整したり、操作を完全に取り消したりする最後の機会を提供します。

Note

実際のアプリケーションでは、ユーザーがカテゴリとサプライヤーを指定できるようにするか、何らかの条件またはビジネス ロジックに基づいてこの値を選択する必要があります (盲目的に ID 1 を選択するのではなく)。 この例では、ObjectDataSource の事前レベル イベントから入力パラメーターの値をプログラムによって設定する方法を示しています。

ObjectDataSource の Inserting イベントのイベント ハンドラーを作成します。 イベント ハンドラーの 2 番目の入力パラメーターは型 ObjectDataSourceMethodEventArgs のオブジェクトであり、パラメーター コレクション (InputParameters) にアクセスするプロパティと、操作を取り消すプロパティ (Cancel) があります。

Protected Sub ObjectDataSource1_Inserting _
    (sender As Object, e As ObjectDataSourceMethodEventArgs) _
    Handles ObjectDataSource1.Inserting

End Sub

この時点で、InputParameters プロパティには、DetailsView から割り当てられた値を持つ ObjectDataSource の InsertParameters コレクションが含まれます。 これらのいずれかのパラメーターの値を変更するには、e.InputParameters("paramName") = value を使用します。 そのため、CategoryIDSupplierID を値 1 に設定するには、Inserting イベント ハンドラーを次のように調整します。

Protected Sub ObjectDataSource1_Inserting _
    (sender As Object, e As ObjectDataSourceMethodEventArgs) _
    Handles ObjectDataSource1.Inserting

    e.InputParameters("CategoryID") = 1
    e.InputParameters("SupplierID") = 1
End Sub

今回は新しい製品 (Acme Soda など) を追加するときに、新製品の CategoryID および SupplierID 列が 1 に設定されます (図 20 を参照)。

新製品の CategoryID と SupplierID の値が 1 に設定されるようになりました

図 20: 新製品の値 CategoryIDSupplierID が 1 に設定されました (クリックするとフルサイズの画像が表示されます)

まとめ

編集、挿入、および削除のプロセス中に、データ Web コントロールと ObjectDataSource の両方で、多くの事前および事後レベルのイベントが処理されます。 このチュートリアルでは、事前レベルのイベントを調べ、これらを使用して入力パラメーターをカスタマイズしたり、データ Web コントロールと ObjectDataSource のイベントの両方からデータ変更操作を完全に取り消す方法を確認しました。 次のチュートリアルでは、事後レベル イベントのイベント ハンドラーの作成と使用について説明します。

プログラミングに満足!

著者について

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

特別な感謝

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