データの挿入、更新、削除の概要 (C#)
このチュートリアルでは、ObjectDataSource の Insert()、Update()、Delete() の各メソッドを BLL クラスのメソッドにマップする方法と、GridView、DetailsView、FormView の各コントロールを構成してデータ変更機能を提供する方法について説明します。
はじめに
過去のいくつかのチュートリアルでは、GridView、DetailsView、FormView の各コントロールを使用して、ASP.NET ページにデータを表示する方法について説明しました。 これらのコントロールは、それらに提供されるデータについてもシンプルに動作します。 通常、これらのコントロールは、ObjectDataSource などのデータ ソース コントロールを使用してデータにアクセスします。 ObjectDataSource が ASP.NET ページと基になるデータの間のプロキシとして機能するしくみについては、既に説明しました。 GridView では、データを表示する必要がある場合、その ObjectDataSource の Select()
メソッドを呼び出します。このメソッドは、ビジネス ロジック レイヤー (BLL) からメソッドを呼び出します。このメソッドは、適切なデータ アクセス層 (DAL) の TableAdapter のメソッドを呼び出し、Northwind データベースに SELECT
クエリを送信します。
最初のチュートリアルで DAL で TableAdapters を作成したときに、Visual Studio によって、基になるデータベース テーブルからデータを挿入、更新、削除するためのメソッドが自動的に追加されたことを思い出してください。 さらに、ビジネス ロジック層の作成では、これらのデータ変更 DAL メソッドを呼び出すメソッドを BLL で設計しました。
ObjectDataSource には、その Select()
メソッドに加えて、Insert()
、Update()
、Delete()
の各メソッドもあります。 Select()
メソッドと同様に、これら 3 つのメソッドは、基になるオブジェクト内のメソッドにマップできます。 データを挿入、更新、削除するように構成されている場合、GridView、DetailsView、FormView の各コントロールでは、基になるデータを変更するためのユーザー インターフェイスが提供されます。 このユーザー インターフェイスは、ObjectDataSource の Insert()
、Update()
、Delete()
の各メソッドを呼び出し、それらによって基になるオブジェクトの関連付けられたメソッドが呼び出されます (図 1 を参照)。
図 1: ObjectDataSource のInsert()
、Update()
、Delete()
の各メソッドは、BLL へのプロキシとして機能する (フルサイズの画像を表示する場合はこちらをクリック)
このチュートリアルでは、ObjectDataSource の Insert()
、Update()
、Delete()
の各メソッドを BLL クラスのメソッドにマップする方法と、GridView、DetailsView、FormView の各コントロールを構成してデータ変更機能を提供する方法について説明します。
手順 1: 挿入、更新、削除のチュートリアル Web ページの作成
データの挿入、更新、削除の方法を調べる前に、まず、このチュートリアルと次のいくつかのページに必要な ASP.NET ページを Web サイト プロジェクトに作成してみましょう。 まず、EditInsertDelete
という名前の新しいフォルダーを追加します。 次に、次の ASP.NET ページをそのフォルダーに追加し、各ページを Site.master
マスター ページに関連付けます。
Default.aspx
Basics.aspx
DataModificationEvents.aspx
ErrorHandling.aspx
UIValidation.aspx
CustomizedUI.aspx
OptimisticConcurrency.aspx
ConfirmationOnDelete.aspx
UserLevelAccess.aspx
図 2: データ変更関連のチュートリアルの ASP.NET ページを追加する
他のフォルダーと同様に、EditInsertDelete
フォルダーの Default.aspx
にチュートリアルが一覧表示されます。 SectionLevelTutorialListing.ascx
ユーザー コントロールでこの機能が提供されていることを思い出してください。 そのため、ソリューション エクスプローラーからページのデザイン ビューにドラッグして、このユーザー コントロールを Default.aspx
に追加します。
図 3: SectionLevelTutorialListing.ascx
ユーザー コントロールを Default.aspx
に追加する (フルサイズの画像を表示する場合はこちらをクリック)
最後に、このページをエントリとして Web.sitemap
ファイルに追加します。 具体的には、Customized Formatting <siteMapNode>
の後に次のマークアップを 追加します。
<siteMapNode title="Editing, Inserting, and Deleting"
url="~/EditInsertDelete/Default.aspx"
description="Samples of Reports that Provide Editing, Inserting,
and Deleting Capabilities">
<siteMapNode url="~/EditInsertDelete/Basics.aspx"
title="Basics"
description="Examines the basics of data modification with the
GridView, DetailsView, and FormView controls." />
<siteMapNode url="~/EditInsertDelete/DataModificationEvents.aspx"
title="Data Modification Events"
description="Explores the events raised by the ObjectDataSource
pertinent to data modification." />
<siteMapNode url="~/EditInsertDelete/ErrorHandling.aspx"
title="Error Handling"
description="Learn how to gracefully handle exceptions raised
during the data modification workflow." />
<siteMapNode url="~/EditInsertDelete/UIValidation.aspx"
title="Adding Data Entry Validation"
description="Help prevent data entry errors by providing validation." />
<siteMapNode url="~/EditInsertDelete/CustomizedUI.aspx"
title="Customize the User Interface"
description="Customize the editing and inserting user interfaces." />
<siteMapNode url="~/EditInsertDelete/OptimisticConcurrency.aspx"
title="Optimistic Concurrency"
description="Learn how to help prevent simultaneous users from
overwritting one another s changes." />
<siteMapNode url="~/EditInsertDelete/ConfirmationOnDelete.aspx"
title="Confirm On Delete"
description="Prompt a user for confirmation when deleting a record." />
<siteMapNode url="~/EditInsertDelete/UserLevelAccess.aspx"
title="Limit Capabilities Based on User"
description="Learn how to limit the data modification functionality
based on the user role or permissions." />
</siteMapNode>
Web.sitemap
を更新した後、ブラウザーでチュートリアル Web サイトの表示を確認してみましょう。 左側のメニューに、チュートリアルの編集、挿入、削除の項目が含まれるようになりました。
図 4: サイト マップにチュートリアルの編集、挿入、削除のエントリが含まれている
手順 2: ObjectDataSource コントロールの追加と構成
GridView、DetailsView、FormView はそれぞれデータ変更機能とレイアウトが異なるため、それぞれを個別に調べてみましょう。 ただし、各コントロールで独自の ObjectDataSource を使用するのではなく、3 つのコントロールの例すべてを共有できる単一の ObjectDataSource を作成します。
Basics.aspx
ページを開き、ツールボックスからデザイナーに ObjectDataSource をドラッグし、スマート タグの [データ ソースの構成] リンクをクリックします。 編集、挿入、削除の各メソッドを提供する BLL クラスは ProductsBLL
のみであるため、ObjectDataSource をこのクラスを使用するように構成します。
図 5: ProductsBLL
クラスを使用するように ObjectDataSource を構成する (フルサイズの画像を表示する場合はこちらをクリック)
次の画面で、ProductsBLL
クラスのどのメソッドが ObjectDataSource の Select()
、Insert()
、Update()
、Delete()
にマップされるかを、適切なタブを選択しドロップダウン リストからメソッドを選択することで指定できます。 図 6 はもう見慣れたことかと思いますが、ObjectDataSource の Select()
メソッドを ProductsBLL
クラスの GetProducts()
メソッドにマップしています。 Insert()
、Update()
、Delete()
の各メソッドは、上部にある一覧から適切なタブを選択して構成できます。
図 6: ObjectDataSource によりすべての製品が返される (フルサイズの画像を表示する場合はこちらをクリック)
図 7、8、9 は、ObjectDataSource の UPDATE、INSERT、DELETE の各タブを示しています。 これらのタブを構成して、Insert()
、Update()
、Delete()
の各メソッドにより、ProductsBLL
クラスの UpdateProduct
、AddProduct
、DeleteProduct
の各メソッドがそれぞれ呼び出されるようにします。
図 7: ObjectDataSource s の Update()
メソッドを ProductBLL
クラスの UpdateProduct
メソッドにマップする (フルサイズの画像を表示する場合はこちらをクリック)
図 8: ObjectDataSource s の Insert()
メソッドを ProductBLL
クラスの Product
メソッドにマップする (フルサイズの画像を表示する場合はこちらをクリック)
図 9: ObjectDataSource s の Delete()
メソッドを ProductBLL
クラスの DeleteProduct
メソッドにマップする (フルサイズの画像を表示する場合はこちらをクリック)
UPDATE タブ、INSERT タブ、DELETE タブのドロップダウン リストで、これらのメソッドが既に選択されていることにお気付きかと思います。 これは ProductsBLL
のメソッドを修飾する DataObjectMethodAttribute
を使用していることによります。 たとえば、DeleteProduct メソッドには次のシグネチャがあります。
[System.ComponentModel.DataObjectMethodAttribute
(System.ComponentModel.DataObjectMethodType.Delete, true)]
public bool DeleteProduct(int productID)
{
...
}
DataObjectMethodAttribute
属性は、各メソッドが選択、挿入、更新、削除のどれを目的としているか、および、それが既定値かどうかを示します。 BLL クラスの作成時にこれらの属性を省略した場合は、UPDATE、INSERT、DELETE の各タブからメソッドを手動で選択する必要があります。
ProductsBLL
のメソッドが適切に ObjectDataSource の Insert()
、Update()
、Delete()
の各メソッドにマップされていることを確認したら、[完了] をクリックしてウィザードを完了します。
ObjectDataSource のマークアップの確認
ウィザードを使用して ObjectDataSource を構成した後、ソース ビューに移動して、生成された宣言型マークアップを調べます。 この <asp:ObjectDataSource>
タグにより、基になるオブジェクトと呼び出すメソッドを指定します。 さらに、ProductsBLL
クラスの AddProduct
、UpdateProduct
、DeleteProduct
の各メソッドの入力パラメーターにマップされる DeleteParameters
、UpdateParameters
、InsertParameters
があります。
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
DeleteMethod="DeleteProduct" InsertMethod="AddProduct"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
<DeleteParameters>
<asp:Parameter Name="productID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<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" />
<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>
ObjectDataSource には、ObjectDataSource が入力パラメーター (GetProductsByCategoryID(categoryID)
など) を想定している select メソッドを呼び出すように構成されている場合に SelectParameter
のリストが存在するのと同様に、関連付けられているメソッドの各入力パラメーターのパラメーターが含まれています。 この後説明しますが、これらの DeleteParameters
、UpdateParameters
、InsertParameters
のそれぞれの値は、ObjectDataSource の Insert()
、Update()
、Delete()
の各メソッドの呼び出しの前に GridView、DetailsView、FormView によって自動的に設定されます。 これらの値は、必要であればプログラムで設定することもできます。詳細についてはこの後のチュートリアルで説明します。
ウィザードを使用して ObjectDataSource を構成する場合の副作用の 1 つは、Visual Studio で OldValuesParameterFormatString プロパティ が original_{0}
に設定されることです。 このプロパティ値は、編集中のデータの元の値を格納するために使用され、次の 2 つのシナリオで役立ちます。
- レコードを編集するときに、ユーザーが主キーの値を変更できる場合。 この場合、新しい主キーの値と元の主キーの値の両方を指定する必要があります。これにより、元の主キーの値をもつレコードを見つけることができ、さらにその値を更新できます。
- オプティミスティック コンカレンシーを使用する場合。 オプティミスティック コンカレンシーは、同時に 2 人のユーザーが互いに変更を上書きしないようにする手法です。この後のチュートリアルのトピックです。
この OldValuesParameterFormatString
プロパティは、基になるオブジェクトの元の値に対する update メソッドと delete メソッドでの入力パラメーターの名前を示します。 このプロパティについては、オプティミスティック コンカレンシーの説明の際に、詳しく説明します。 ただし、ここでは、BLLのメソッドが元の値を想定しておらず、したがってこのプロパティを削除することが重要であるため、取り上げています。 この OldValuesParameterFormatString
プロパティを既定値 ({0}
) 以外に設定すると、データ Web コントロールが ObjectDataSource の Update()
メソッドまたは Delete()
メソッドを呼び出そうとするときにエラーが発生します。これは、ObjectDataSource が指定された UpdateParameters
または DeleteParameters
と、元の値のパラメーターの両方を渡そうとするためです。
この段階であまり明確な理解に至っていないとしても、問題はありません。このプロパティとそのユーティリティについては、この後のチュートリアルで確認します。 ここでは、宣言構文からこのプロパティ宣言を完全に削除するか、値を既定値 ({0}) に設定する、ということだけ確実に行ってください。
Note
デザイン ビューのプロパティ ウィンドウから OldValuesParameterFormatString
プロパティ値を単にクリアすると、プロパティは宣言構文にまだ存在しますが、空の文字列に設定されます。 この場合、残念ながら上記と同じ問題が引き続き発生します。 したがって、宣言構文からプロパティを完全に削除するか、プロパティ ウィンドウから値を既定値の {0}
に設定します。
手順 3: データ Web コントロールの追加とデータ変更用の構成
ObjectDataSource がページに追加され構成されたことで、データ Web コントロールをページに追加して、データを表示し、エンド ユーザーが変更できるようにする準備ができました。 GridView、DetailsView、FormView を個別に見ていきます。これらのデータ Web コントロールは、データ変更機能と構成がそれぞれ異なるためです。
この記事の後半で説明しますが、GridView、DetailsView、FormView の各コントロールを使用して非常に基本的な編集、挿入、削除のサポートを追加することは、いくつかのチェックボックスをオンにするほど簡単です。 現実的には、数多くの微妙なケースやエッジ ケースがあり、そうした場合に対応する機能を提供するには、単なるポイントアンドクリックよりも込み入った手順が必要となります。 ただし、このチュートリアルでは、シンプルなデータ変更機能の提供のみに焦点を当てています。 この後のチュートリアルでは、実際の環境でたいへんありがちな懸念事項について説明します。
GridView からのデータの削除
まず、ツールボックスからデザイナーに GridView をドラッグします。 次に、ObjectDataSource を GridView にバインドします。これは、GridView のスマート タグのドロップダウン リストから選択して行います。 この時点で、GridView の宣言型マークアップは次のようになります。
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ProductID"
InsertVisible="False"
ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName"
SortExpression="ProductName" />
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
SortExpression="SupplierID" />
<asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
SortExpression="CategoryID" />
<asp:BoundField DataField="QuantityPerUnit"
HeaderText="QuantityPerUnit"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock"
HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder"
HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" />
<asp:BoundField DataField="ReorderLevel"
HeaderText="ReorderLevel" SortExpression="ReorderLevel" />
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued" />
<asp:BoundField DataField="CategoryName"
HeaderText="CategoryName" ReadOnly="True"
SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName"
HeaderText="SupplierName" ReadOnly="True"
SortExpression="SupplierName" />
</Columns>
</asp:GridView>
スマート タグを使用して GridView を ObjectDataSource にバインドすることには、次の 2 つの利点があります。
- BoundFields と CheckBoxFields が ObjectDataSource によって返される各フィールドに対して自動的に作成されます。 さらに、BoundField と CheckBoxField のプロパティは、基になるフィールドのメタデータに基づいて設定されます。 たとえば、
ProductID
、CategoryName
、SupplierName
の各フィールドはProductsDataTable
で読み取り専用としてマークされているため、編集時に更新不可となります。 これに対応するために、これらの BoundFields の ReadOnly プロパティ はtrue
に設定されます。 - DataKeyNames プロパティは、基になるオブジェクトの主キー フィールドに割り当てられます。 これは、GridView を使用してデータを編集または削除する場合に不可欠です。このプロパティは、各レコードを一意に識別するフィールド (または一連のフィールド) を示します。 この
DataKeyNames
プロパティの詳細については、「選択可能なマスター GridView と詳細 DetailView を使用してマスター/詳細を表示する」チュートリアルを参照してください。
GridView は、プロパティ ウィンドウまたは宣言構文を使用して ObjectDataSource にバインドできますが、これを行うには、適切な BoundField と DataKeyNames
マークアップを手動で追加する必要があります。
GridView コントロールには、行レベルの編集と削除が組み込みでサポートされています。 削除をサポートするように GridView を構成すると、[削除] ボタンの列が追加されます。 エンド ユーザーが特定の行の [削除] ボタンをクリックすると、ポストバックが発生し、GridView によって次の手順が実行されます。
- ObjectDataSource の
DeleteParameters
値が割り当てられる - ObjectDataSource の
Delete()
メソッドが呼び出され、指定したレコードが削除される - GridView は、その
Select()
メソッドを呼び出して ObjectDataSource に再バインドする
DeleteParameters
に割り当てられる値は、[削除] ボタンがクリックされた行の DataKeyNames
フィールドの値です。 そのため、GridViewの DataKeyNames
プロパティが適切に設定されていることが重要です。 これがない場合、DeleteParameters
には手順 1 で null
値が割り当てられます。その結果、手順 2 でレコードが削除されることはありません。
Note
DataKeys
コレクションは GridView のコントロール状態に格納されます。つまり、GridView のビュー状態が無効になっている場合でも、DataKeys
の値はポストバック全体で記憶されます。 ただし、編集または削除をサポート (既定の動作) する GridView に対してビュー状態が有効のままになっていることが非常に重要です。 GridView の EnableViewState
プロパティを false
に設定すると、1 人のユーザーに対して編集と削除の動作は正常に機能しますが、同時実行ユーザーがデータを削除しようとしている場合、これらの同時実行ユーザーが意図していないレコードを誤って削除または編集する可能性があります。
この同じ警告は、DetailsViews と FormViews にも適用されます。
GridView に削除機能を追加するには、そのスマート タグに移動し、[削除を有効にする] チェックボックスをオンにします。
図 10: [削除を有効にする] チェック ボックスをオンにする
スマート タグから [削除を有効にする] チェックボックスをオンにすると、GridView に CommandField が追加されます。 CommandField では、GridView の列に、レコードの選択、レコードの編集、レコードの削除の 1 つ以上のタスクを実行するためのボタンがレンダリングされます。 ここまでに、「選択可能なマスター GridView と詳細 DetailView を使用してマスター/詳細を表示する」のチュートリアルで、レコードの選択を行う CommandField の動作を確認しました。
CommandField には、CommandField にどのような一連のボタンが表示されるかを示す多くの ShowXButton
プロパティが含まれています。 [削除を有効にする] チェックボックスをオンにすることで、ShowDeleteButton
プロパティが true
に設定されている CommandField が GridView の列に追加されます。
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:CommandField ShowDeleteButton="True" />
... BoundFields removed for brevity ...
</Columns>
</asp:GridView>
GridView への削除のサポートの追加は、これだけで完了です。 図 11 に示すように、ブラウザーからこのページにアクセスすると、[削除] ボタンの列が表示されます。
図 11: CommandField に削除ボタンの列が追加される (フルサイズの画像を表示する場合はこちらをクリック)
このチュートリアルを独力で一から作成している場合は、このページをテストするときに [削除] ボタンをクリックすると例外が発生します。 これらの例外が発生した理由とその修正方法については、引き続き読み進めてください。
Note
このチュートリアルに付属しているダウンロードを使用して従っている場合、これらの問題は既に対応済みです。 ただし、発生する可能性のある問題と適切な回避策を特定するために、以下に示す詳細を読み進めていただくことをお勧めします。
製品を削除しようとするときに、"ObjectDataSource 'ObjectDataSource1' でパラメーター: productID が original_ProductID である非ジェネリック メソッド 'DeleteProduct' が見つかりませんでした" のようなメッセージの例外が発生する場合は、ObjectDataSource から OldValuesParameterFormatString
プロパティを削除するのを忘れた可能性があります。 OldValuesParameterFormatString
プロパティが指定されていると、ObjectDataSource は productID
と original_ProductID
の両方の入力パラメーターを DeleteProduct
メソッドに渡そうとします。 しかし、DeleteProduct
では受け入れる入力パラメーターは 1 つだけであり、例外となります。 OldValuesParameterFormatString
プロパティを削除 (または {0}
に設定) すると、ObjectDataSource に対して、元の入力パラメーターを渡さないように指示することになります。
図 12: OldValuesParameterFormatString
プロパティがクリアされていることを確認する (フルサイズの画像を表示する場合はこちらをクリック)
OldValuesParameterFormatString
プロパティを適切に削除した場合でも、製品を削除しようとするときに "DELETE ステートメントが REFERENCE 制約 'FK_Order_Details_Products' と競合しました。" のメッセージで引き続き例外が発生することがあります。Northwind データベースには、Order Details
テーブルと Products
テーブルの間に外部キー制約が含まれています。これは、Order Details
テーブルに 1 つ以上のレコードがある場合、製品をシステムから削除することはできないということを意味しています。 Northwind データベース内のすべての製品には Order Details
に少なくとも 1 つのレコードがあるため、製品に関連付けられている注文詳細レコードを最初に削除するまで、製品を削除することはできません。
図 13: 外部キー制約により、製品の削除が抑止される (フルサイズの画像を表示する場合はこちらをクリック)。
このチュートリアルでは、Order Details
テーブルからすべてのレコードを削除してみましょう。 実際のアプリケーションでは、次のいずれかが必要です。
- 注文の詳細情報を管理する別の画面を用意する
- 指定した製品の注文の詳細を削除するロジックを含むように
DeleteProduct
メソッドを拡張する - TableAdapter で使用される SQL クエリを変更して、指定した製品の注文の詳細の削除を含める
外部キー制約を回避するために、Order Details
テーブルからすべてのレコードを削除してみましょう。 Visual Studio でサーバー エクスプローラーに移動し、NORTHWND.MDF
ノードを右クリックして、[新しいクエリ] を選択します。 次に、クエリ ウィンドウで、次の SQL ステートメントを実行します: DELETE FROM [Order Details]
図 14: Order Details
テーブルからすべてのレコードを削除する (フルサイズの画像を表示する場合はこちらをクリック)
[削除] ボタンをクリックして Order Details
テーブルをクリアすると、製品が削除されます。エラーは発生しません。 [削除] ボタンをクリックしても製品が削除されない場合は、GridView の DataKeyNames
プロパティが主キー フィールド (ProductID
) に設定されていることを確認します。
Note
[削除] ボタンをクリックするとポストバックが発生し、レコードが削除されます。 これは危険な場合があります。間違った行の [削除] ボタンを誤ってクリックすることは、簡単に起こりえます。 この後のチュートリアルでは、レコードを削除するときにクライアント側の確認を追加する方法について説明します。
GridView を使用したデータの編集
GridView コントロールでは、削除に加えて、組み込みの行レベルの編集もサポートされています。 編集をサポートするように GridView を構成すると、[編集] ボタンの列が追加されます。 エンド ユーザーから見ると、行の [編集] ボタンをクリックすると、その行が編集可能になり、セルが既存の値を含むテキスト ボックスに変化し、[編集] ボタンが [更新] ボタンと [キャンセル] ボタンに置き換えられます。 必要な変更を行った後、エンド ユーザーは [更新] ボタンをクリックして変更をコミットすることも、[キャンセル] ボタンをクリックして変更を取り消すこともできます。 どちらの場合も、[更新] または [キャンセル] をクリックすると、GridView は編集を開始する前の状態に戻ります。
ページ開発者から見ると、エンド ユーザーが特定の行の [編集] ボタンをクリックするとポストバックが発生し、GridView は次の手順を実行します。
- GridView の
EditItemIndex
プロパティは、[編集] ボタンがクリックされた行のインデックスに割り当てられる - GridView は、その
Select()
メソッドを呼び出して ObjectDataSource に再バインドする EditItemIndex
に一致する行インデックスが、"編集モード" でレンダリングされる。このモードでは、[編集] ボタンが [更新] ボタンと [キャンセル] ボタンに置き換えられ、ReadOnly
プロパティが False (既定値) である BoundFields が、Text
プロパティがデータ フィールドの値に割り当てられている TextBox Web コントロールとしてレンダリングされる。
この時点で、マークアップがブラウザーに返され、エンド ユーザーは行のデータを変更できます。 ユーザーが [更新] ボタンをクリックすると、ポストバックが発生し、GridView によって次の手順が実行されます。
- ObjectDataSource の
UpdateParameters
値には、エンド ユーザーが GridView の編集インターフェイスに入力した値が割り当てられる - ObjectDataSource の
Update()
メソッドが呼び出され、指定したレコードが更新される - GridView は、その
Select()
メソッドを呼び出して ObjectDataSource に再バインドする
手順 1 で UpdateParameters
に割り当てられる主キーの値は、DataKeyNames
プロパティで 指定された値から取得されますが、主キー以外の値は、編集された行の TextBox Web コントロールのテキストから取得されます。 削除と同様に、GridViewの DataKeyNames
プロパティを適切に設定することが重要です。 これがない場合、UpdateParameters
主キーの値には手順 1 で null
値が割り当てられます。その結果、手順 2 でレコードが更新されることはありません。
編集機能は、GridView のスマート タグの [編集の有効化] チェックボックスをオンにするだけでアクティブ化できます。
図 15: [編集の有効化] チェック ボックスをオンにする
[編集の有効化] チェックボックスをオンにすると、CommandField が (必要であれば) 追加され、その ShowEditButton
プロパティが true
に設定されます。 これまで見てきたとおり、CommandField には、CommandField にどのような一連のボタンが表示されるかを示す多くの ShowXButton
プロパティが含まれています。 [編集の有効化] チェックボックスをオンにすると、既存のCommandField に ShowEditButton
プロパティが追加されます。
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:CommandField ShowDeleteButton="True"
ShowEditButton="True" />
... BoundFields removed for brevity ...
</Columns>
</asp:GridView>
基本的な編集サポートを追加する方法はこれですべてです。 図 16 に示すように、編集インターフェイスは、ReadOnly
プロパティが false
(既定値) に設定されているそれぞれの BoundField が TextBox としてレンダリングされる、やや粗削りなものです。 これには、他のテーブルのキーである CategoryID
や SupplierID
のようなフィールドが含まれます。
図 16: Chai の [編集] ボタンをクリックすると、編集モードで行が表示される (フルサイズの画像を表示する場合はこちらをクリック)
外部キー値を直接編集するようユーザーに求めるというだけでなく、編集インターフェイスのインターフェイスには次のような点で欠けていることがあります。
- ユーザーがデータベースに存在しない
CategoryID
やSupplierID
を入力する場合、UPDATE
が外部キー制約の違反となり、例外が発生する。 - 編集インターフェイスには一切の検証が含まれていない。 必須の値 (
ProductName
など) を指定しない場合、または数値が想定されているところに文字列値を入力する場合 (UnitPrice
テキスト ボックスに 「Too much!」と入力するなど)、例外がスローされる。 この後のチュートリアルで、編集ユーザー インターフェイスに検証コントロールを追加する方法について説明します。 - 現在のところ、読み取り専用ではない "すべての" 製品フィールドは GridView に含まれている必要がある。 たとえば、データを更新するときに
UnitPrice
GridView からフィールドを削除すると、GridView はUnitPrice
UpdateParameters
値を設定せず、データベース レコードのUnitPrice
をNULL
値に変更します。 同様に、GridView から必須フィールド (たとえばProductName
) が削除された場合、上記と同じく、"列 'ProductName' に null を使用することはできません" 例外で更新が失敗する。 - 編集インターフェイスの書式設定には、手を加える余地が大きく残っている。
UnitPrice
には小数点が 4 つ表示される。 理想的には、CategoryID
とSupplierID
の値には、システム内のカテゴリとサプライヤーを一覧表示する DropDownList が含まれることが望ましい。
これらはすべて、現時点ではがまんして使用しなければならない欠点です。この後のチュートリアルで取り上げます。
DetailsView を使用したデータの挿入、編集、削除
ここまでのチュートリアルで説明したように、DetailsView コントロールでは、一度に 1 つのレコードを表示し、GridView と同様に、現在表示されているレコードの編集と削除を行うことができます。 DetailsView の項目の編集と削除に関するエンド ユーザーのエクスペリエンスと、ASP.NET 側からのワークフローは、共に GridView のそれと同じです。 DetailsView が GridView と異なるのは、組み込みの挿入サポートも提供するという点です。
GridView のデータ変更機能を示すために、まず、Basics.aspx
ページに、既存の GridView の上に DetailsView を追加し、DetailsView のスマート タグを使用して既存の ObjectDataSource にバインドします。 次に、DetailsView の Height
プロパティと Width
プロパティをクリアし、スマート タグから [ページングの有効化] オプションをオンにします。 編集、挿入、削除のサポートを有効にするには、スマート タグの [編集の有効化]、[挿入の有効化]、[削除の有効化] の各チェックボックスをオンにするだけです。
図 17: 編集、挿入、削除をサポートするように DetailsView を構成する
GridView と同様に、次の宣言構文に示すように、編集、挿入、削除のサポートを追加すると、DetailsView に CommandField が追加されます。
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True">
<Fields>
<asp:BoundField DataField="ProductID"
HeaderText="ProductID" InsertVisible="False"
ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName"
HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
SortExpression="SupplierID" />
<asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
SortExpression="CategoryID" />
<asp:BoundField DataField="QuantityPerUnit"
HeaderText="QuantityPerUnit"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice"
HeaderText="UnitPrice" SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock"
HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder"
HeaderText="UnitsOnOrder" SortExpression="UnitsOnOrder" />
<asp:BoundField DataField="ReorderLevel"
HeaderText="ReorderLevel" SortExpression="ReorderLevel" />
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued" />
<asp:BoundField DataField="CategoryName"
HeaderText="CategoryName" ReadOnly="True"
SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName"
HeaderText="SupplierName" ReadOnly="True"
SortExpression="SupplierName" />
<asp:CommandField ShowDeleteButton="True"
ShowEditButton="True" ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
DetailsView の場合、CommandField は既定で Columns コレクションの末尾に表示されることに注目してください。 DetailsView のフィールドは行としてレンダリングされるため、CommandField は DetailsView の下部に [挿入]、[編集]、[削除] の各ボタンを含む行として表示されます。
図 18: DetailsView を構成して編集、挿入、削除をサポートする (フルサイズの画像を表示する場合はこちらをクリック)
[削除] ボタンをクリックすると、GridView と同じイベント シーケンス (ポストバック) が開始されます。続いて DetailsView が DataKeyNames
の値に基づいて ObjectDataSource の DeleteParameters
にデータを 設定し、ObjectDataSource の Delete()
メソッドを呼び出して完了します。これにより、実際にデータベースから製品が削除されます。 DetailsView での編集も、GridView と同じしくみで動作します。
挿入の場合、エンド ユーザーに対して [新規] ボタンが表示されます。このボタンをクリックすると、DetailsView が "挿入モード" でレンダリングされます。"挿入モード" では、[新規] ボタンは [挿入] ボタンと [キャンセル] ボタンに置き換えられ、InsertVisible
プロパティが true
(既定値) に設定されている BoundFields のみが表示されます。 自動インクリメント フィールドとして識別されるこれらのデータ フィールド (ProductID
など) は、スマート タグを使用して DetailsView をデータ ソースにバインドする際に InsertVisible プロパティ が false
に設定されます。
スマート タグを使用してデータ ソースを DetailsView にバインドするときに、Visual Studio では、自動インクリメント フィールドに対してのみ InsertVisible
プロパティが false
に設定されます。 CategoryName
や SupplierName
のような読み取り専用フィールドは、InsertVisible
プロパティが明示的に false
に設定されていない限り、"挿入モード" ユーザー インターフェイスに表示されます。 DetailsView の宣言構文、またはスマート タグの [フィールドの編集] リンクを使用して、この 2 つの InsertVisible
フィールドのプロパティを false
に設定します。 図 19 では、[フィールドの編集] リンクをクリックして InsertVisible
プロパティを false
に設定するところを示しています。
図 19: Northwind Traders で Acme Tea が提供されるようになる (フルサイズの画像を表示する場合はこちらをクリック)
InsertVisible
プロパティを設定したら、ブラウザーで Basics.aspx
ページを表示し、[新規] ボタンをクリックします。 図 20 は、新しい飲料 Acme Tea を製品ラインに追加する際の DetailsView を示しています。
図 20: Northwind Traders で Acme Tea が提供されるようになる (フルサイズの画像を表示する場合はこちらをクリック)
Acme Tea の詳細を入力して [挿入] ボタンをクリックすると、ポストバックが実行され、新しいレコードが Products
データベース テーブルに追加されます。 この DetailsView には、データベース テーブルに存在する製品が順に一覧表示されるため、新しい製品を表示するには最後の製品にページ移動する必要があります。
図 21: Acme Tea の詳細 (フルサイズの画像を表示する場合はこちらをクリック)
Note
DetailsView の CurrentMode プロパティは、表示されているインターフェイスを示し、次のいずれかの値となります: Edit
、Insert
、ReadOnly
。 DefaultMode プロパティは、編集または挿入が完了した後に DetailsView が戻るモードを示し、DetailsView を編集モードまたは挿入モードで永続的に表示する場合に便利です。
DetailsView のポイント アンド クリック挿入機能と編集機能には、GridView と同じ制限がかかります。ユーザーはテキスト ボックスを使用して既存の CategoryID
と SupplierID
の値を入力しなければならない、インターフェイスには検証ロジックが欠落している、NULL
値が許可されない、またはデータベース レベルで指定された既定値がないすべての製品フィールドを挿入インターフェイスに含める必要がある、などです。
この後の記事で扱う、GridView の編集インターフェイスを拡張し強化するための手法は、DetailsView コントロールの編集インターフェイスと挿入インターフェイスにも適用できます。
より柔軟なデータ変更ユーザー インターフェイスのための FormView の使用
FormView には、データの挿入、編集、削除のためのサポートが組み込まれていますが、フィールドの代わりにテンプレートを使用するため、データ変更インターフェイスを提供するために GridView コントロールと DetailsView コントロールで使用される BoundFields や CommandField を追加する余地がありません。 代わりに、このインターフェイスでは、新しい項目を追加するとき、または既存の項目を編集するときに、ユーザー入力を収集するために、[新規]、[編集]、[削除]、[挿入]、[更新]、および [キャンセル] ボタンを適切なテンプレートに手動で追加する必要があります。 さいわい、Visual Studio では、スマート タグのドロップダウン リストを使用して FormView をデータ ソースにバインドするときに、必要なインターフェイスが自動的に作成されます。
これらの手法を説明するには、まず Basics.aspx
ページに FormView を追加し、FormView のスマート タグから、既に作成されている ObjectDataSource にバインドします。 これにより、ユーザーの入力と [新規]、[編集]、[削除]、[挿入]、[更新]、[キャンセル] の各ボタンに対するボタン Web コントロールを収集するための、TextBox Web コントロールを含む FormView に対して、EditItemTemplate
、InsertItemTemplate
、ItemTemplate
が生成されます。 さらに、FormView の DataKeyNames
プロパティは、ObjectDataSource によって返されるオブジェクトの主キー フィールド (ProductID
) に設定されます。 最後に、FormView のスマート タグ内の [ページングの有効化] チェック ボックスをオンにします。
FormView が ObjectDataSource にバインドされた後の FormView の ItemTemplate
の宣言型マークアップを次に示します。 既定では、ブール値以外の各製品フィールドはラベル Web コントロールの Text
プロパティにバインドされ、各ブール値フィールド (Discontinued
) は無効になっている CheckBox Web コントロールの Checked
プロパティにバインドされます。 [新規]、[編集]、[削除] の各ボタンがクリックされたときに特定の FormView 動作をトリガーするには、CommandName
値が、それぞれ New
、Edit
、Delete
に設定されている必要があります。
<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1" AllowPaging="True">
<EditItemTemplate>
...
</EditItemTemplate>
<InsertItemTemplate>
...
</InsertItemTemplate>
<ItemTemplate>
ProductID:
<asp:Label ID="ProductIDLabel" runat="server"
Text='<%# Eval("ProductID") %>'></asp:Label><br />
ProductName:
<asp:Label ID="ProductNameLabel" runat="server"
Text='<%# Bind("ProductName") %>'>
</asp:Label><br />
SupplierID:
<asp:Label ID="SupplierIDLabel" runat="server"
Text='<%# Bind("SupplierID") %>'>
</asp:Label><br />
CategoryID:
<asp:Label ID="CategoryIDLabel" runat="server"
Text='<%# Bind("CategoryID") %>'>
</asp:Label><br />
QuantityPerUnit:
<asp:Label ID="QuantityPerUnitLabel" runat="server"
Text='<%# Bind("QuantityPerUnit") %>'>
</asp:Label><br />
UnitPrice:
<asp:Label ID="UnitPriceLabel" runat="server"
Text='<%# Bind("UnitPrice") %>'></asp:Label><br />
UnitsInStock:
<asp:Label ID="UnitsInStockLabel" runat="server"
Text='<%# Bind("UnitsInStock") %>'>
</asp:Label><br />
UnitsOnOrder:
<asp:Label ID="UnitsOnOrderLabel" runat="server"
Text='<%# Bind("UnitsOnOrder") %>'>
</asp:Label><br />
ReorderLevel:
<asp:Label ID="ReorderLevelLabel" runat="server"
Text='<%# Bind("ReorderLevel") %>'>
</asp:Label><br />
Discontinued:
<asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
Checked='<%# Bind("Discontinued") %>'
Enabled="false" /><br />
CategoryName:
<asp:Label ID="CategoryNameLabel" runat="server"
Text='<%# Bind("CategoryName") %>'>
</asp:Label><br />
SupplierName:
<asp:Label ID="SupplierNameLabel" runat="server"
Text='<%# Bind("SupplierName") %>'>
</asp:Label><br />
<asp:LinkButton ID="EditButton" runat="server"
CausesValidation="False" CommandName="Edit"
Text="Edit">
</asp:LinkButton>
<asp:LinkButton ID="DeleteButton" runat="server"
CausesValidation="False" CommandName="Delete"
Text="Delete">
</asp:LinkButton>
<asp:LinkButton ID="NewButton" runat="server"
CausesValidation="False" CommandName="New"
Text="New">
</asp:LinkButton>
</ItemTemplate>
</asp:FormView>
図 22 は、ブラウザーで表示された場合の FormView の ItemTemplate
を示しています。 各製品フィールドは、下部の [新規]、[編集]、[削除] ボタンと共に一覧表示されます。
図 22: 既定の FormView ItemTemplate
に、各製品フィールドが [新規]、[編集]、[削除] の各ボタンと共に一覧表示される (フルサイズの画像を表示する場合はこちらをクリック)
GridView や DetailsView と同様に、[削除] ボタン、または CommandName
プロパティが Delete に設定されている任意の Button、LinkButton、または ImageButton をクリックすると、ポストバックが発生し、FormView の DataKeyNames
の値に基づいて ObjectDataSource の DeleteParameters
が設定され、ObjectDataSource の Delete()
メソッドが呼び出されます。
[編集] ボタンをクリックするとポストバックが発生し、データが EditItemTemplate
に再バインドされ、これにより編集インターフェイスのレンダリングが行われます。 このインターフェイスには、[更新] ボタンと [キャンセル] ボタンと共にデータを編集するための Web コントロールが含まれています。 Visual Studio によって生成される既定値 EditItemTemplate
には、自動インクリメント フィールド (ProductID
) の Label、ブール値以外の各フィールドの TextBox、および各ブール値フィールドの CheckBox が含まれます。 この動作は、GridView コントロールと DetailsView コントロールで自動生成された BoundFields によく似ています。
Note
FormView の EditItemTemplate
の自動生成に関する小さな問題の1 つは、CategoryName
や SupplierName
: .などの読み取り専用のフィールドのための TextBox Web コントロールがレンダリングされることです。 これに対処する方法についてはこの後説明します。
EditItemTemplate
のTextBox コントロールには、"双方向データ バインド" を使用して対応するデータ フィールドの値にバインドされる Text
プロパティがあります。 <%# Bind("dataField") %>
で示される双方向データ バインドでは、テンプレートにデータをバインドするときと、レコードを挿入または編集するための ObjectDataSource のパラメーターを設定する場合の両方で、データ バインドが行われます。 つまり、ユーザーが ItemTemplate
から [編集] ボタンをクリックすると、Bind()
メソッドは指定されたデータ フィールドの値を返します。 ユーザーが変更を行い、[更新] をクリックすると、Bind()
を使用して指定したデータ フィールドに対応するポストバックされた値が ObjectDataSource の UpdateParameters
に適用されます。 それに対して、<%# Eval("dataField") %>
で示される一方向データ バインドでは、テンプレートにデータをバインドする際にのみデータ フィールドの値を取得し、ポストバック時にユーザーが入力した値をデータ ソースのパラメーターに "返しません"。
次の宣言型マークアップは、FormView の EditItemTemplate
を示しています。 この Bind()
メソッドは、ここでのデータ バインド構文で使用され、Update Button Web コントロールと Cancel Button Web コントロールの CommandName
プロパティが適宜設定されていることに注目してください。
<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1" AllowPaging="True">
<EditItemTemplate>
ProductID:
<asp:Label ID="ProductIDLabel1" runat="server"
Text="<%# Eval("ProductID") %>"></asp:Label><br />
ProductName:
<asp:TextBox ID="ProductNameTextBox" runat="server"
Text="<%# Bind("ProductName") %>">
</asp:TextBox><br />
SupplierID:
<asp:TextBox ID="SupplierIDTextBox" runat="server"
Text="<%# Bind("SupplierID") %>">
</asp:TextBox><br />
CategoryID:
<asp:TextBox ID="CategoryIDTextBox" runat="server"
Text="<%# Bind("CategoryID") %>">
</asp:TextBox><br />
QuantityPerUnit:
<asp:TextBox ID="QuantityPerUnitTextBox" runat="server"
Text="<%# Bind("QuantityPerUnit") %>">
</asp:TextBox><br />
UnitPrice:
<asp:TextBox ID="UnitPriceTextBox" runat="server"
Text="<%# Bind("UnitPrice") %>">
</asp:TextBox><br />
UnitsInStock:
<asp:TextBox ID="UnitsInStockTextBox" runat="server"
Text="<%# Bind("UnitsInStock") %>">
</asp:TextBox><br />
UnitsOnOrder:
<asp:TextBox ID="UnitsOnOrderTextBox" runat="server"
Text="<%# Bind("UnitsOnOrder") %>">
</asp:TextBox><br />
ReorderLevel:
<asp:TextBox ID="ReorderLevelTextBox" runat="server"
Text="<%# Bind("ReorderLevel") %>">
</asp:TextBox><br />
Discontinued:
<asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
Checked="<%# Bind("Discontinued") %>" /><br />
CategoryName:
<asp:TextBox ID="CategoryNameTextBox" runat="server"
Text="<%# Bind("CategoryName") %>">
</asp:TextBox><br />
SupplierName:
<asp:TextBox ID="SupplierNameTextBox" runat="server"
Text="<%# Bind("SupplierName") %>">
</asp:TextBox><br />
<asp:LinkButton ID="UpdateButton" runat="server"
CausesValidation="True" CommandName="Update"
Text="Update">
</asp:LinkButton>
<asp:LinkButton ID="UpdateCancelButton" runat="server"
CausesValidation="False" CommandName="Cancel"
Text="Cancel">
</asp:LinkButton>
</EditItemTemplate>
<InsertItemTemplate>
...
</InsertItemTemplate>
<ItemTemplate>
...
</ItemTemplate>
</asp:FormView>
この時点で、EditItemTemplate
を使用しようとすると例外がスローされます。 問題は、CategoryName
フィールドと SupplierName
フィールドが EditItemTemplate
で TextBox Web コントロールとしてレンダリングされるということです。 これらの TextBox は、Label に変更するか、完全に削除する必要があります。 EditItemTemplate
からそれらを完全に削除することにしましょう.
図 23 は、Chai の [編集] ボタンがクリックされた後のブラウザーの FormView を示しています。 ItemTemplate
に表示されている SupplierName
フィールドと CategoryName
フィールドが、EditItemTemplate
から削除した結果、存在しなくなったことに注目してください。 [更新] ボタンをクリックすると、FormView は GridView コントロールや DetailsView コントロールと同じ一連の手順を実行します。
図 23: 既定では、EditItemTemplate
には各編集可能な製品フィールドが TextBox または CheckBox として表示される (フルサイズの画像を表示する場合はこちらをクリック)
[挿入] ボタンをクリックすると、FormView の ItemTemplate
によりポストバックが実行されます。 ただし、新しいレコードが追加されようとしているため、データは FormView にバインドされません。 この InsertItemTemplate
インターフェイスには、[挿入] ボタンと [キャンセル] ボタンと共に、新しいレコードを追加するための Web コントロールが含まれています。 Visual Studio によって生成される既定の InsertItemTemplate
には、自動生成された EditItemTemplate
のインターフェイスと同様に、ブール値以外の各フィールドの TextBox とブール値の各フィールドの CheckBox が含まれます。 TextBox コントロールには、双方向データ バインドを使用して対応するデータ フィールドの値にバインドされる Text
プロパティがあります。
次の宣言型マークアップは、FormView の InsertItemTemplate
を示しています。 この Bind()
メソッドは、ここでのデータ バインド構文で使用され、Insert Button Web コントロールと Cancel Button Web コントロールの CommandName
プロパティが適宜設定されていることに注目してください。
<asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1" AllowPaging="True">
<EditItemTemplate>
...
</EditItemTemplate>
<InsertItemTemplate>
ProductName:
<asp:TextBox ID="ProductNameTextBox" runat="server"
Text="<%# Bind("ProductName") %>">
</asp:TextBox><br />
SupplierID:
<asp:TextBox ID="SupplierIDTextBox" runat="server"
Text="<%# Bind("SupplierID") %>">
</asp:TextBox><br />
CategoryID:
<asp:TextBox ID="CategoryIDTextBox" runat="server"
Text="<%# Bind("CategoryID") %>">
</asp:TextBox><br />
QuantityPerUnit:
<asp:TextBox ID="QuantityPerUnitTextBox" runat="server"
Text="<%# Bind("QuantityPerUnit") %>">
</asp:TextBox><br />
UnitPrice:
<asp:TextBox ID="UnitPriceTextBox" runat="server"
Text="<%# Bind("UnitPrice") %>">
</asp:TextBox><br />
UnitsInStock:
<asp:TextBox ID="UnitsInStockTextBox" runat="server"
Text="<%# Bind("UnitsInStock") %>">
</asp:TextBox><br />
UnitsOnOrder:
<asp:TextBox ID="UnitsOnOrderTextBox" runat="server"
Text="<%# Bind("UnitsOnOrder") %>">
</asp:TextBox><br />
ReorderLevel:
<asp:TextBox ID="ReorderLevelTextBox" runat="server"
Text="<%# Bind("ReorderLevel") %>">
</asp:TextBox><br />
Discontinued:
<asp:CheckBox ID="DiscontinuedCheckBox" runat="server"
Checked="<%# Bind("Discontinued") %>" /><br />
CategoryName:
<asp:TextBox ID="CategoryNameTextBox" runat="server"
Text="<%# Bind("CategoryName") %>">
</asp:TextBox><br />
SupplierName:
<asp:TextBox ID="SupplierNameTextBox" runat="server"
Text="<%# Bind("SupplierName") %>">
</asp:TextBox><br />
<asp:LinkButton ID="InsertButton" runat="server"
CausesValidation="True" CommandName="Insert"
Text="Insert">
</asp:LinkButton>
<asp:LinkButton ID="InsertCancelButton" runat="server"
CausesValidation="False" CommandName="Cancel"
Text="Cancel">
</asp:LinkButton>
</InsertItemTemplate>
<ItemTemplate>
...
</ItemTemplate>
</asp:FormView>
FormView の InsertItemTemplate
の自動生成には細かい注意点があります。 具体的には、TextBox Web コントロールは、CategoryName
や SupplierName
のような読み取り専用のフィールドに対しても作成されます。 EditItemTemplate
と同様に、これらの TextBox を InsertItemTemplate
から削除する必要があります。
図 24 は、新しい製品 Acme Coffee を追加するときのブラウザーの FormView を示しています。 ItemTemplate
に表示されている SupplierName
フィールドと CategoryName
フィールドが、削除の結果、存在しなくなったことに注目してください。 [挿入] ボタンをクリックすると、FormView は DetailsView コントロールと同じ一連の手順を実行し、Products
テーブルに新しいレコードを追加します。 図 25 は、挿入後の FormView の Acme Coffee 製品の詳細を示しています。
図 24: InsertItemTemplate
によって FormView の挿入インターフェイスが制御される (フルサイズの画像を表示する場合はこちらをクリック)
図 25: 新しい製品 Acme Coffee の詳細が FormView に表示される (フルサイズの画像を表示する場合はこちらをクリック)
FormView では、読み取り専用、編集、挿入の各インターフェイスを 3 つの異なるテンプレートに分離することで、DetailsView や GridView よりも細やかなインターフェイスの制御が可能です。
Note
DetailsView と同様に、FormView の CurrentMode
プロパティは表示されているインターフェイスを示し、その DefaultMode
プロパティは、編集または挿入が完了した後に FormView が戻るモードを示します。
まとめ
このチュートリアルでは、GridView、DetailsView、FormView を使用したデータの挿入、編集、削除の基本について説明しました。 これらの 3 つのコントロールはすべて、データ Web コントロールと ObjectDataSource の機能に依拠して、ASP.NET ページで 1 行のコードも記述することなく利用できる、ある程度のレベルの組み込みデータ変更機能を提供します。 ただし、単純なポイント アンド クリックの手法では、かなり貧弱で単純なデータ変更ユーザー インターフェイスがレンダリングされます。 検証を提供したり、プログラム値を挿入したり、例外を適切に処理したり、ユーザー インターフェイスをカスタマイズしたりするには、後続のチュートリアルで説明する手法に頼る必要があります。
プログラミングに満足!
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。