DataGridにレコードを削除する機能を追加したサンプル

図 DataGridにレコードを削除する機能を追加したサンプル
このサンプルは、親ウィンドウのDataGridからレコードを選択して子ウィンドウから削除することができます。子ウィンドウから削除したレコードは、親ウィンドウのDataGridから消去されます。
レコードを削除するには、親ウィンドウに表示されているDataGridからレコードを選択します。次に、親ウィンドウからレコードの削除ボタン
をクリックします。子ウィンドウに、選択したレコードが表示されたら[削除]ボタンをクリックします。子ウィンドウから削除ボタンをクリックすると、子ウィンドウは自動的に閉じられます。レコードの削除をキャンセルするときは、子ウィンドウから[閉じる]ボタンをクリックします。
子ウィンドウから削除したレコードは、親ウィンドウのDataGridから消去されます。DataGridには、得意先テーブルのレコードが得意先IDの降順に10件表示されます。
◆プログラムPopupDelete.aspxのポイント
¶ポイント1 削除するレコードをポップアップウィンドウで確認するには
Web Matrixのテンプレートを使用すれば、DataGridにレコードを削除する機能を簡単に追加することができます。ところが、DataGridに削除機能を組み込んだ場合、確認の問い合わせをしないで削除するため、誤って別のレコードを削除する可能性があります。このサンプルでは、レコードの削除ボタンをクリックしたとき、子ウィンドウに削除されるレコードを表示します。子ウィンドウから削除されるレコードを確認したら、子ウィンドウの削除ボタンをクリックします。これで、レコードがデータベースから削除されます。子ウィンドウから削除したレコードは、親ウィンドウのDataGridから消去されます。
¶ポイント2 削除するレコードがに変更されているときの対処
このサンプルでは、削除したレコードをデータベースに反映するのにDataAdapterのUpdate()メソッドを使用しています。Update()メソッドは、DataTableからレコードが削除されたとき、SQLのDELETEステートメントを実行してデータベースから削除します。DataTableからレコードを削除したときは、削除フラグが付けられるだけでレコードは存在します。
Update()メソッドは、レコードが他のクライアントから変更されていたり、削除されているとき、「同時実行違反」のエラーとします。このサンプルでは、レコードが他のクライアントからすでに削除されているときのみ「同時実行違反」にします。レコードが他のクライアントから変更されているときは、削除を受け付けます。このサンプルでは、「同時実行違反」のとき「すでに削除済みです!」のエラーとします。
削除するレコードがすでに変更されているとき、「同時実行違反」にする方法については、後述するNoteにて解説します。
¶ポイント3 ConcurrencyIDを使用してDELETEステートメントを高速化するには
CommandBuilderは、DataAdapterのSelectCommandに格納されているSELECTステートメントを元にDELETEステートメントを生成します。たとえば、SELECT CustomerID FROM CustomersのようなSQLが格納されているときは、以下のようなDELETEステートメントが生成されます。
DELETE FROM Customers
WHERE ((CustomerID=?))
SELECT * FROM Customersのように、すべてのカラム(フィールド)を指定したときは、DELETEステートメントのWHERE句にすべてのカラムが抽出条件として指定されます。この場合、レコードが変更されていないときのみ削除されます。ConcurrencyIDを使用すると、これと同等の処理を高速化できます。ConcurrencyIDには、レコードの更新回数が格納されています。
DELETE FROM Customers
WHERE ((CustomersID=?) And (ConcurrencyID=?))
◆メインプログラムDataGridDelete.aspxの解説(HTML編)
親ウィンドウのWebフォームには、ImageButtonとDataGridを作成しています。ImageButtonでは、レコードの削除ボタンを表示します。このボタンをクリックすると、子ウィンドウが開きます。DataGridには、得意先テーブルのレコードを得意先IDの降順に10件表示します。
行162-168では、ImageButtonを定義しています。行164では、OnCommandイベントを登録しています。このイベントでは、子ウィンドウを開きます。
162: <asp:ImageButton
id="ibtnDelete" runat="server"
163:
CommandName="delete"
164:
OnCommand="ibtnDelete_Command"
165:
ImageUrl="../img/delete.gif"
168:
ImageAlign="Middle" />
行169-175では、LabelとTextBoxを定義してDataGridの件数を表示しています。TextBoxのReadOnlyプロパティには、Trueを設定して読み込み専用にしています。TextBoxには、ランタイム時にレコード件数を設定します。
169: <asp:Label
id="lblRo
170:
Text="件数"
171:
CssClass="rowNumber" />
172: <asp:TextBox id="txtRo
174:
Columns="3"
175:
ReadOnly="True" />
行188-240では、DataGridを定義しています。このDataGridでは、AutoGenerateColumnsプロパティにFalseを設定してカラムの自動生成機能を抑止しています。行202-239の<Columns>…</Columns>では、TemplateColumnとBoundColumnを定義しています。TemplateColumnのItemTemplateでは、LinkButtonを定義しています。LinkButtonは、レコードセレクターとして使用します。BoundColumnでは、得意先テーブルの得意先ID、得意先名、担当者名、役職、電話番号、都道府県をバインドしています。
202: <Columns>
203: <asp:TemplateColumn
204:
HeaderText="<div
class='dgrdHeaderBox'>1</div>">
205:
<ItemTemplate>
206:
<asp:LinkButton id="lbtnSelect" runat="server"
207:
CommandName="Select"
208:
Text="<div class='dgrdItemArrow'>4</div>"
209:
Visible="True" />
210:
</ItemTemplate>
213:
</asp:TemplateColumn>
214: <asp:BoundColumn
ItemStyle-Width="20"
215:
DataField="CustomerID"
216:
HeaderText="<div class='dgrdHeader'>ID</div>">
218:
</asp:BoundColumn>
・・・
239: </Columns>
行249-254では、TextBoxを定義しています。このTextBoxは、メッセージを表示するのと、Webページをポストバックさせる役割をします。
249: <asp:TextBox id="txtMessage"
runat="server"
252: Columns="107"
253: Visible="True"
254: ReadOnly="True" />
行259-262では、Buttonを定義しています。このButtonもWebページをポストバックさせる役割をします。
259: <asp:Button id="btnRefresh"
runat="server"
260: Text="Hidden"
261: Visible="False"
262:
OnClick="btnRefresh_Click" />
リスト DataGridDelete.aspxのソースコード(HTML編)
|
143:
<html> 239: </Columns> |
◆メインプログラムDataGridDelete.aspxの解説(コード編)
DataGridDelete.aspxは、DataGrid上に得意先テーブルを表示します。DataGridからレコードを選択して、削除ボタンをクリックすると、子ウィンドウを開きます。また、子ウィンドウと連携して、子ウィンドウから削除したレコードをDataGridに反映する処理も行っています。
Sub Page_Load()イベントの処理
このイベントは、DataGridDelete.aspxがロードされたときに実行されます。このイベントでは、クライアント側で動作するイベントの登録と、DataGridに得意先テーブルをバインドします。
行11では、メッセージを表示するTextBoxにクライアント側で動作する、onPropertyChangeイベントを登録しています。onProperyChangeイベントでは、Webページをポストバックします。GetPostBackEventReference()メソッドは、WebページをポストバックするJavaScriptを生成します。Webページがポストバックされると、btnRefreshイベントが実行されます。
行12-21のIf…Else…End Ifでは、ページが最初にロードされたか調べています。ページが最初にロードされたときは、Vie
|
10: Sub Page_Load() |
Sub dgrdCustomers_ItemDataBound()イベントの処理
このイベントは、DataGridのDataBind()メソッドが実行されたときに発生します。このイベントでは、DataGridのアイテム(DataGridItem)にクライアント側で動作するonClickイベントを登録しています。これにより、DataGridの任意のセルをクリックして行を選択できるようになります。
|
46: Sub
dgrdCustomers_ItemDataBound(s As Object, e As DataGridItemEventArgs) |
Sub dgrdCustomers_ItemCommand()イベントの処理
このイベントは、DataGridから行をクリックしたときに発生します。このイベントでは、DataGridから選択した行の情報をVie
行60では、DataGridのDataKeysコレクションから、選択された行の主キー(得意先ID)を取得しています。Item.ItemIndexには、選択されたアイテムのインデックス番号が格納されています。行61では、得意先IDをVie
|
58: Sub
dgrdCustomers_ItemCommand(s As Object, e As DataGridCommandEventArgs) 63: End If |
Sub ibtnDelete_Command()イベントの処理
このイベントは、Webページからレコードの削除ボタンをクリックしたときに発生します。このイベントでは、レコード削除用の新規ウィンドウを表示します。
行67-69のIf…End Ifでは、DataGridから削除するレコードを選択しているか調べています。レコードが選択されているときは、InsertScriptBlock()関数を呼び出して新規ウィンドウを開きます。この関数の引数には、削除するレコードの得意先IDを指定します。
|
66: Sub
ibtnDelete_Command(s As Object, e As CommandEventArgs) |
Sub btnRefresh_Click()イベントの処理
このイベントは、クライアント側からメッセージを表示するTextBoxを書き換えたときに発生します。このサンプルでは、子ウィンドウから親ウィンドウのTextBoxにメッセージを設定して書き換えます。つまり、子ウィンドウから親ウィンドウをポストバックさせています。btnRefresh_Clickイベントでは、DataGridに得意先テーブルをバインドしてリフレッシュします。
行30-32のIf…End Ifでは、DataGridのItems.Countプロパティに格納されているアイテム件数が0か調べています。アイテム件数が0のときは、イベントを終了します。行33-35では、選択された行がアイテム件数を超えているか調べています。選択されている行がアイテム件数を超えているときは、先頭のアイテムを選択行にします。
|
24: Sub
btnRefresh_Click(s As Object, e As EventArgs) |
Sub BindDataGrid()の処理
このサブプロシージャでは、DataGridに得意先テーブルをバインドして表示します。BindDataGridは、Page_Loadイベントから呼ばれます。
行73では、得意先テーブルからレコードを抽出するSQLを生成しています。このSQLでは、Order By句で「CustomerID Desc」を指定していますので、得意先IDの降順にレコードが並べ替えられます。また、Top 10のオプションを指定していますので、上位10件のレコードが抽出されます。
行74では、CreateDataSet()関数を呼び出して得意先テーブルのDataSetを作成しています。行76では、DataSetのTablesコレクションからDataTableを作成しています。行77では、DataTableのPrimaryKeyプロパティに得意先IDのDataColumnを設定しています。PrimaryKeyに主キーを設定することにより、DataTableのRo
行79-86のWith…End Withでは、DataGridにDataTableをバインドしています。行83では、DataGridのSelectedIndexプロパティに0を設定して、DataGridの先頭行を選択した状態にしています。行84-85では、先頭行の得意先IDを取得してVie
行88では、件数のTextBoxにレコード件数を設定しています。行89では、Session変数にDataTableを保存しています。ここで保存したSession変数は、ポストバックされたときと、サブプログラムから参照します。
|
72: Sub BindDataGrid() |
Sub InsertScriptBlock()の処理
このサブプロシージャでは、新規ウィンドウを開くJavaScriptを生成して登録します。InsertScriptBlockは、レコードの削除ボタンをクリックしたときに、削除ボタンのOnCommandイベントから呼ばれます。
行93-95では、JavaScriptのwindow.open()メソッドの引数に指定するオプションを生成しています。行97-101のWith…End Withでは、StringBuilderのAppend()メソッドで以下のJavaScriptを生成しています。
<script
language='javascript'>
window.open('PopupDelete.aspx?id=9999','_blank','features');
</script>
JavaScriptのwindow.open()メソッドは、新規ウィンドウを開きます。Open()メソッドの引数には、url、target、featuresを指定します。urlには、新規ウィンドウに表示するファイルPopupDelete.aspxを指定します。?id=9999は、QueryStringと呼ばれるパラメータです。このサンプルでは、親ウィンドウから子ウィンドウにデータを渡すのにQueryStringを使用します。id=には、更新するレコードの得意先IDを指定します。
行102では、Page.RegisterClientScriptBlock()メソッドでJavaScriptを登録します。ここで登録したJavaScriptは、Webページがロードされたときにクライアント側のブラウザから実行されます。
|
92: Sub
InsertScriptBlock(intCustomerID As Integer)
|
Sub InsertAlertScript()の処理
このサブプロシージャでは、エラーメッセージをポップアップウィンドウに表示するJavaScriptを生成して登録します。InsertAlertScriptは、CreateDataSet()関数からエラーが発生したときに呼ばれます。ここで登録したJavaScriptは、Webページがロードされたときにクライアント側のブラウザから実行されます。
|
105:
Sub InsertAlertScript(strMessage As String) |
Function CreateDataSet()関数の処理
この関数は、DataSetを作成して返します。CreateDataSetは、BindDataGrid()から呼ばれます。
行128-129では、Connectionのインスタンスを生成しています。Connectionの引数には、Web.Configに登録されているデータベース接続文字列を指定しています。Web.Configに登録されている内容を取得するには、ConfigurationSettingsのAppSettings()メソッドを使用します。AppSettings()メソッドの引数には、<add>タグのkeyを指定します。
128: Dim con As New OleDbConnection( _
129:
ConfigurationSettings.AppSettings("conStringAccNw"))
<appSettings>
<add key="conStringAccNw"
value="PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA Source=C:\WebMatrix\webdb\Nwind.mdb" />
</appSettings>
行130では、DataAdapterのインスタンスを生成しています。DataAdapterの引数には、SQLとConnectionオブジェクトを指定しています。
行132-137のTry…Catch…End Tryブロックでは、DataAdapterのFill()メソッドでSQLを実行して得意先テーブルをDataSetに取り込んでいます。行132-133のTryブロックでエラーが発生したときは、行134-136のCatchブロックが実行されます。Catchブロックでは、InsertAlertScript()を呼び出してポップアップウィンドウにエラーメッセージを表示します。
132: Try
133: da.Fill(ds)
134: Catch e As Exception
135:
InsertAlertScript(e.Message)
136: Return Nothing
137: End Try
行138では、関数の戻り値としてDataSetを返します。
|
126:
Function CreateDataSet(strSQL As String, _ |
リスト DataGridDelete.aspxのソースコード(コード編)
|
1: <%@ Page
language="vb" SmartNavigation="false" %> 118: Optional strConnectionString As
String = "conStringAccNw") As OleDbDataReader 127: Optional strConnectionString As
String = "conStringAccNw") As DataSet |
◆サブプログラムPopupDelete.aspxの解説(HTML編)
子ウィンドウのWebフォームには、TextBoxとButtonを作成しています。TextBoxには、削除される得意先レコードが表示されますので確認することができます。
行93-104の<tr>…</tr>では、得意先IDのLabelとTextBoxを定義しています。TextBoxには、得意先レコードの得意先IDが表示されます。TextBoxのReadOnlyプロパティにTrueを設定して読み込み専用にしています。
後続する<tr>…</tr>では、得意先名、担当者名、部署役職、電話番号のLabelとTextBoxを定義しています。
行192-199では、「削除」と「閉じる」のボタンを定義しています。
リスト PopupDelete.aspxのソースコード(HTML編)
|
78: <html> 158: </table> |
◆サブプログラムPopupDelete.aspxの解説(コード編)
PopupDelete.aspxは、Webフォームから削除したレコードを2段階でデータベースに反映します。Webフォームから削除したレコードは、DataTable上で削除フラグが付けられます。次に、DataTableの削除フラグが付けられたレコードをデータベースから抹消します。データベースからレコードを抹消したら、親ウィンドウをポストバックさせてDataGridをリフレッシュします。
Sub Page_Load()イベントの処理
このイベントは、ページがロードされたときに発生します。Page_Loadでは、ページの初期化処理を行います。
行9では、Session変数に保存されている得意先テーブルのDataTableを取得して変数に退避します。
行10-13のIf…EndIfでは、ページが最初にロードされたか調べています。最初にロードされたときは、「閉じる」ボタンにクライアント側で動作するonClickイベントを登録しています。onClickイベントでは、JavaScriptのwindow.close()メソッドを実行して子ウィンドウを閉じます。次に、DisplayRecord()を呼び出してTextBoxに得意先レコードを表示します。
|
8: Sub Page_Load() |
Sub btnDelete_Click()イベントの処理
このイベントは、削除ボタンをクリックしたときに発生します。このイベントでは、得意先テーブルのレコードを削除します。また、ここで削除したレコードを親ウィンドウのDataGridから消去します。
行17では、DeleteRecord()関数を呼び出して得意先テーブルのレコードを削除します。DeleteRecordからは、処理の結果がメッセージで返されます。行19-29のWith…End Withでは、StringBuilderのAppend()メソッドで以下のJavaScriptを生成しています。
<script
language='javascript'>
window.opener.frmMain.txtMessage.value
= 'message';
alert('message'); or
window.close();
</script>"
JavaScriptのwindow.opener.frmMain.txtMessage.value=は、親ウィンドウのtxtMessage.valueにメッセージを設定します。txtMessageには、クライアント側で動作するonProperyChangeイベントが登録されていますので、このイベントが実行されます。onPropertyChangeイベントには、WebページをポストバックさせるJavaScriptが記述されていますので、WebページがポストバックされてDataGridがリフレッシュされます。
JavaScriptのalert()関数は、「同時実行違反」のエラーが発生したときに生成されます。alert()関数は、ポップアップウィンドウにエラーメッセージを表示します。window.close()は、レコードが正常に削除されたときに生成されます。
行30では、Page.RegisterClientScriptBlock()メソッドでJavaScriptを登録しています。ここで登録したJavaScriptは、Webページがロードされたときクライアント側のブラウザから実行されます。
|
16: Sub btnDelete_Click(s
As Object, e As EventArgs) |
Sub DisplayRecord()の処理
このサブプロシージャでは、TextBoxに得意先テーブルのレコードを表示します。DisplayRecordは、Page_Loadイベントからページが最初にロードされたときに呼ばれます。
行34では、RequestのParamsコレクションからQueryStingに指定しているパラメータを取得しています。QueryStringには、親ウィンドウのDataGridから選択したレコードの得意先IDが指定されています。Request.Params()の代わりにRequest.QueryString()を使用することもできます。
PupupUpdate.aspx?id=9999
Request.Params("id") è 9999
Request.QueryString("id") è 9999
行35では、DataTableのRo
行36-42のIf…End Ifでは、レコードが見つかったか調べています。レコードが見つかったときは、DataRowから得意先ID、得意先名、担当者名、部署役職、電話番号を取得してTextBoxに表示します。担当者名、役職部署、電話番号は、Nullの可能性があるためDataRowのIsNull()メソッドで調べています。Nullのときは、空白を表示します。
|
33: Sub DisplayRecord() |
Function DeleteRecord()関数の処理
この関数では、DataTableのレコードに削除フラグを付けて削除します。DeleteRecord()は、削除ボタンのOnClickイベントから呼ばれます。
行50では、DataTableのRo
|
45: Function DeleteRecord()
As String |
Function UpdateDataTable()関数の処理
この関数では、DataTableの削除フラグが付いたレコードをデータベースから抹消します。この関数は、DeleteRecord()から呼ばれます。UpdateDataTable()の引数には、strSQLとstrConnectionStringを指定します。strSQLには、得意先テーブルからレコードを抽出するSQLを指定します。strConnectionStringには、データベースの接続文字列を指定します。DataTableをデータベースに反映するには、DataAdapterのUpdate()メソッドを使用します。Update()メソッドで使用するINSERT、UPDATE、DELETEのSQLは、CommandBuilderで自動生成します。
行61-62では、Connectionのインスタンスを生成しています。Connectionの引数には、データベースの接続文字列を指定します。行63では、DataAdapterのインスタンスを生成しています。DataAdapterの引数には、SQLとConnectionのオブジェクトを指定します。引数のSQLには、SELECTステートメントを指定します。行64では、CommandBuilderでDataTableをデータベースに反映するためのSQLを自動生成します。CommandBuilderは、SELECTステートメントを元にINSERT、UPDATE、DELETEのSQLを生成します。
行67-72のTry…Catch…End Tryブロックでは、DataAdapterのUpdate()メソッドでDataTableの削除フラグが付いているレコードをデータベースから抹消します。DataTableのレコードが削除されたときは、DELETEステートメントで、データベースからレコードを抹消します。このサンプルでは、レコードが存在するときすでに変更されていても抹消します。レコードが存在しないときは、「すでに削除済みです!」のエラーとします。
Update()メソッドでエラーが発生したときは、行70-71のCatchブロックが実行されます。行73では、戻り値として処理の結果を示すメッセージを返します。
「すでに削除済みです!」のエラーが発生したときは、ポップアップウィンドウにエラーメッセージを表示します。このとき、親ウィンドウのDataGridには最新のデータが表示されますので、目的のレコードは消去されます。「すでに削除済みです!」のエラーが表示されたときは、子ウィンドウの「閉じる」ボタンをクリックしてキャンセルします。
|
59: Function
UpdateDataTable(strSQL As String, _ |
リスト PopupDelete.aspxのソースコード(コード編)
|
1: <%@ Page language="vb"
SmartNavigation="False" %> |
Note
|
削除するレコードがすでに変更されているとき、同時実行違反とするには DataAdapterのSelectCommandにSelect CustomerID From Customersを設定して、CommandBuilderを実行すると以下のようなDELETEステートメントが生成されます。 Dim strSQL As String = "Select CustomerID From Customers" Dim con As New OleDbConnection( _ ConfigurationSettings.AppSettings(strConnectionString)) Dim da As New OleDbDataAdapter(strSQL, con) Dim cb As New OleDbCommandBuilder(da) DELETEステートメント: DELETE FROM Customers WHERE ( (CustomerID = ?) ) DELETEステートメントのWHERE句にはCustomerID=?のみ指定されていますので、得意先IDがデータベースに存在するときに無条件に削除されます。レコードが他のクライアントから変更されていないか確認してから削除するには、DataAdapterのSelectCommandにSelect * From CustomersのようなSQLを設定してから、CommandBuilderを実行します。この場合、DELETEステートメントのWHERE句には、レコードのすべてのフィールドが指定されます。つまり、レコードが変更されていないときのみ削除されるようになります。 CommandBuilder方式は、レコードのフィールド数が多いとき効率が悪いので、ConcurrencyIDを使用した方式に改善します。ConcurrencyIDには、レコードの更新回数が格納されます。 DELETEステートメントのWHERE句にConcurrencyIDを追加するには、CommandBuilderを使用しないで手動にてDELETEステートメントを作成します。 da.DeleteCommand = CreateDeleteCommand() Function CreateDeleteCommand() As OleDbCommand Dim sbSQL As New StringBuilder() With sbSQL .Append("Delete From Customers " & vbCrLf) .Append(" Where CustomerID = ? And " & vbCrLf) .Append(" ConcurrencyID = ? ") End With Dim cmd As New OleDbCommand(sbSQL.ToString, mcon) Dim pc As OleDbParameterCollection = cmd.Parameters Dim param As OleDbParameter With pc param = .Add("@OrgCustomerID", OleDbType.Integer, 0, "CustomerID") param.SourceVersion = DataRowVersion.Original param = .Add("@OrgConcurrencyID", OleDbType.Integer, 0, "ConcurrencyID") param.SourceVersion = DataRowVersion.Original End With Return cmd End Function DataRowVersion.Originalは、パレメータ変数@OrgCustomerIDと@OrgConcurrencyIDに変更前の値を代入することを意味します。 |
Tip
|
削除ボタンに確認の問い合わせを追加するには 削除ボタンをクリックしたときに確認の問い合わせをするには、Page_Loadイベントで以下のコードを追加します。 btnDelete.Attributes.Add("onClick", "return confirm('削除してよろしいですか?');") |