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

 

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

 

このサンプルは、親ウィンドウのDataGridからレコードを選択して子ウィンドウから削除することができます。子ウィンドウから削除したレコードは、親ウィンドウのDataGridから消去されます。

 

レコードを削除するには、親ウィンドウに表示されているDataGridからレコードを選択します。次に、親ウィンドウからレコードの削除ボタンをクリックします。子ウィンドウに、選択したレコードが表示されたら[削除]ボタンをクリックします。子ウィンドウから削除ボタンをクリックすると、子ウィンドウは自動的に閉じられます。レコードの削除をキャンセルするときは、子ウィンドウから[閉じる]ボタンをクリックします。

 

子ウィンドウから削除したレコードは、親ウィンドウのDataGridから消去されます。DataGridには、得意先テーブルのレコードが得意先IDの降順に10件表示されます。

 

 

◆プログラムPopupDelete.aspxのポイント

 

¶ポイント1 削除するレコードをポップアップウィンドウで確認するには

 

Web Matrixのテンプレートを使用すれば、DataGridにレコードを削除する機能を簡単に追加することができます。ところが、DataGridに削除機能を組み込んだ場合、確認の問い合わせをしないで削除するため、誤って別のレコードを削除する可能性があります。このサンプルでは、レコードの削除ボタンをクリックしたとき、子ウィンドウに削除されるレコードを表示します。子ウィンドウから削除されるレコードを確認したら、子ウィンドウの削除ボタンをクリックします。これで、レコードがデータベースから削除されます。子ウィンドウから削除したレコードは、親ウィンドウのDataGridから消去されます。

 

¶ポイント2 削除するレコードがに変更されているときの対処

 

このサンプルでは、削除したレコードをデータベースに反映するのにDataAdapterUpdate()メソッドを使用しています。Update()メソッドは、DataTableからレコードが削除されたとき、SQLDELETEステートメントを実行してデータベースから削除します。DataTableからレコードを削除したときは、削除フラグが付けられるだけでレコードは存在します。

 

Update()メソッドは、レコードが他のクライアントから変更されていたり、削除されているとき、「同時実行違反」のエラーとします。このサンプルでは、レコードが他のクライアントからすでに削除されているときのみ「同時実行違反」にします。レコードが他のクライアントから変更されているときは、削除を受け付けます。このサンプルでは、「同時実行違反」のとき「すでに削除済みです!」のエラーとします。

 

削除するレコードがすでに変更されているとき、「同時実行違反」にする方法については、後述するNoteにて解説します。

 

¶ポイント3 ConcurrencyIDを使用してDELETEステートメントを高速化するには

 

CommandBuilderは、DataAdapterSelectCommandに格納されている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フォームには、ImageButtonDataGridを作成しています。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では、LabelTextBoxを定義してDataGridの件数を表示しています。TextBoxReadOnlyプロパティには、Trueを設定して読み込み専用にしています。TextBoxには、ランタイム時にレコード件数を設定します。

 

169:     <asp:Label id="lblRows" runat="server"
170:       Text="
件数"
171:       CssClass="rowNumber" />
172:     <asp:TextBox id="txtRows" runat="server"
174:       Columns="3"
175:       ReadOnly="True" />

 

188-240では、DataGridを定義しています。このDataGridでは、AutoGenerateColumnsプロパティにFalseを設定してカラムの自動生成機能を抑止しています。行202-239<Columns>…</Columns>では、TemplateColumnBoundColumnを定義しています。TemplateColumnItemTemplateでは、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を定義しています。このButtonWebページをポストバックさせる役割をします。

 

259: <asp:Button id="btnRefresh" runat="server"
260:   Text="Hidden"
261:   Visible="False"
262:   OnClick="btnRefresh_Click" />

 

 

リスト DataGridDelete.aspxのソースコード(HTML編)

143: <html>
149: <body scroll="no">
158: <form id="frmMain" runat="server">
162: <asp:ImageButton id="ibtnDelete" runat="server"
163:   CommandName="delete"
164:   OnCommand="ibtnDelete_Command"
165:   ImageUrl="../img/delete.gif"
168:   ImageAlign="Middle" />
169: <asp:Label id="lblRows" runat="server"
170:   Text="
件数"
171:   CssClass="rowNumber" />
172: <asp:TextBox id="txtRows" runat="server"
174:   Columns="3"
175:   ReadOnly="True" />
188: <asp:DataGrid id="dgrdCustomers" runat="server"
189:   AutoGenerateColumns="False"
190:   OnItemCommand="dgrdCustomers_ItemCommand"
191:   OnItemDataBound="dgrdCustomers_ItemDataBound"
192:   OnItemCreated="dgrdCustomers_ItemCreated"
197:   EnableViewState="True">
         
・・・
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>
240: </asp:DataGrid>
249: <asp:TextBox id="txtMessage" runat="server"
252:   Columns="107"
253:   Visible="True"
254:   ReadOnly="True" />
259: <asp:Button id="btnRefresh" runat="server"
260:   Text="Hidden"
261:   Visible="False"
262:   OnClick="btnRefresh_Click" />
263: </form>
264: </body>
264: </html>

 

 

◆メインプログラムDataGridDelete.aspxの解説(コード編)

 

DataGridDelete.aspxは、DataGrid上に得意先テーブルを表示します。DataGridからレコードを選択して、削除ボタンをクリックすると、子ウィンドウを開きます。また、子ウィンドウと連携して、子ウィンドウから削除したレコードをDataGridに反映する処理も行っています。

 

Sub Page_Load()イベントの処理

 

このイベントは、DataGridDelete.aspxがロードされたときに実行されます。このイベントでは、クライアント側で動作するイベントの登録と、DataGridに得意先テーブルをバインドします。

 

11では、メッセージを表示するTextBoxにクライアント側で動作する、onPropertyChangeイベントを登録しています。onProperyChangeイベントでは、Webページをポストバックします。GetPostBackEventReference()メソッドは、WebページをポストバックするJavaScriptを生成します。Webページがポストバックされると、btnRefreshイベントが実行されます。

 

12-21If…Else…End Ifでは、ページが最初にロードされたか調べています。ページが最初にロードされたときは、ViewStateDataGridから選択した行の得意先IDを保存します。ページがポストバックされたときは、ViewStateから得意先IDを取得して変数に保存します。さらに、Session変数に保存されているDataTableを取得して変数に退避します。Session変数にDataTableが保存されていないときは、BindDataGrid()を呼び出します。BindDataGridでは、得意先テーブルのDataTableを作成してDataGridにバインドします。

 

10: Sub Page_Load()
 11:   txtMessage.Attributes.Add("OnPropertyChange", GetPostBackEventReference(btnRefresh))
 12:   If Not IsPostBack Then
 13:     ViewState("CustomerID") = mintCustomerID
 14:     BindDataGrid()
 15:   Else
 16:     mintCustomerID = ViewState("CustomerID")
 17:     mdt = CType(Session("Customers"), DataTable)
 18:     If mdt Is Nothing Then
 19:       BindDataGrid()
 20:     End If
 21:   End If
 22: End Sub

 

 

Sub dgrdCustomers_ItemDataBound()イベントの処理

 

このイベントは、DataGridDataBind()メソッドが実行されたときに発生します。このイベントでは、DataGridのアイテム(DataGridItem)にクライアント側で動作するonClickイベントを登録しています。これにより、DataGridの任意のセルをクリックして行を選択できるようになります。

 

46: Sub dgrdCustomers_ItemDataBound(s As Object, e As DataGridItemEventArgs)
 47:   Dim lit As ListItemType = e.Item.ItemType
 48:
 49:   If lit = ListItemType.Item OrElse _
 50:     lit = ListItemType.AlternatingItem OrElse _
 51:     lit = ListItemType.SelectedItem Then
 52:     Dim lbtn As LinkButton = CType(e.Item.FindControl("lbtnSelect"), LinkButton)
 53:     e.Item.Attributes("onClick") = GetPostBackClientHyperlink(lbtn, "")
 54:     e.Item.Style("cursor") = "hand"
 55:   End If
 56: End Sub

 

 

Sub dgrdCustomers_ItemCommand()イベントの処理

 

このイベントは、DataGridから行をクリックしたときに発生します。このイベントでは、DataGridから選択した行の情報をViewStateに保存します。

 

60では、DataGridDataKeysコレクションから、選択された行の主キー(得意先ID)を取得しています。Item.ItemIndexには、選択されたアイテムのインデックス番号が格納されています。行61では、得意先IDViewStateに保存しています。ViewStateに保存した得意先IDは、レコードの削除ボタンをクリックしたときに参照します。

 

58: Sub dgrdCustomers_ItemCommand(s As Object, e As DataGridCommandEventArgs)
 59:   If e.CommandName = "Select" Then
 60:     mintCustomerID = dgrdCustomers.DataKeys(e.Item.ItemIndex)
 61:     ViewState("CustomerID") = mintCustomerID

 63:   End If
 64: End Sub

 

 

Sub ibtnDelete_Command()イベントの処理

 

このイベントは、Webページからレコードの削除ボタンをクリックしたときに発生します。このイベントでは、レコード削除用の新規ウィンドウを表示します。

 

67-69If…End Ifでは、DataGridから削除するレコードを選択しているか調べています。レコードが選択されているときは、InsertScriptBlock()関数を呼び出して新規ウィンドウを開きます。この関数の引数には、削除するレコードの得意先IDを指定します。

 

66: Sub ibtnDelete_Command(s As Object, e As CommandEventArgs)
 67:   If dgrdCustomers.SelectedIndex <> -1 Then
 68:     InsertScriptBlock(mintCustomerID)
 69:   End If
 70: End Sub

 

 

Sub btnRefresh_Click()イベントの処理

 

このイベントは、クライアント側からメッセージを表示するTextBoxを書き換えたときに発生します。このサンプルでは、子ウィンドウから親ウィンドウのTextBoxにメッセージを設定して書き換えます。つまり、子ウィンドウから親ウィンドウをポストバックさせています。btnRefresh_Clickイベントでは、DataGridに得意先テーブルをバインドしてリフレッシュします。

 

30-32If…End Ifでは、DataGridItems.Countプロパティに格納されているアイテム件数が0か調べています。アイテム件数が0のときは、イベントを終了します。行33-35では、選択された行がアイテム件数を超えているか調べています。選択されている行がアイテム件数を超えているときは、先頭のアイテムを選択行にします。

 

 

24: Sub btnRefresh_Click(s As Object, e As EventArgs)
 25:   BindDataGrid()
 26:   With dgrdCustomers
 27:     .DataSource = mdt
 28:     .DataKeyField = "CustomerID"
 29:     .DataBind()
 30:     If .Items.Count = 0 Then
 31:       Exit Sub
 32:     End If
 33:     If .SelectedIndex > .Items.Count - 1 Then
 34:       .SelectedIndex = 0
 35:     End If
 36:     mintCustomerID = .DataKeys(.SelectedIndex)
 37:     ViewState("CustomerID") = mintCustomerID
 38:     txtRows.Text = .Items.Count.ToString()
 39:   End With
 40: End Sub

 

 

Sub BindDataGrid()の処理

 

このサブプロシージャでは、DataGridに得意先テーブルをバインドして表示します。BindDataGridは、Page_Loadイベントから呼ばれます。

 

73では、得意先テーブルからレコードを抽出するSQLを生成しています。このSQLでは、Order By句で「CustomerID Desc」を指定していますので、得意先IDの降順にレコードが並べ替えられます。また、Top 10のオプションを指定していますので、上位10件のレコードが抽出されます。

 

74では、CreateDataSet()関数を呼び出して得意先テーブルのDataSetを作成しています。行76では、DataSetTablesコレクションからDataTableを作成しています。行77では、DataTablePrimaryKeyプロパティに得意先IDDataColumnを設定しています。PrimaryKeyに主キーを設定することにより、DataTableRowsコレクションのFind()メソッドを使用することができます。

 

79-86With…End Withでは、DataGridDataTableをバインドしています。行83では、DataGridSelectedIndexプロパティに0を設定して、DataGridの先頭行を選択した状態にしています。行84-85では、先頭行の得意先IDを取得してViewStateに保存しています。ここで保存したViewStateは、ポストバックされたときに参照します。

 

88では、件数のTextBoxにレコード件数を設定しています。行89では、Session変数にDataTableを保存しています。ここで保存したSession変数は、ポストバックされたときと、サブプログラムから参照します。

 

72: Sub BindDataGrid()
 73:   Dim strSQL As String = "Select top 10 * From Customers Order by CustomerID Desc"
 74:   Dim ds AS DataSet = CreateDataSet(strSQL)
 75:
 76:   mdt = ds.Tables(0)
 77:   mdt.PrimaryKey = New DataColumn() {mdt.Columns("CustomerID")}
 78:
 79:   With dgrdCustomers
 80:     .DataSource = mdt
 81:     .DataKeyField = "CustomerID"
 82:     .DataBind()
 83:     .SelectedIndex = 0
 84:     mintCustomerID = .DataKeys(0)
 85:     ViewState("CustomerID") = mintCustomerID
 86:   End With
 87:
 88:   txtRows.Text = mdt.Rows.Count.ToString()
 89:   Session("Customers") = mdt
 90: End Sub

 

 

Sub InsertScriptBlock()の処理

 

このサブプロシージャでは、新規ウィンドウを開くJavaScriptを生成して登録します。InsertScriptBlockは、レコードの削除ボタンをクリックしたときに、削除ボタンのOnCommandイベントから呼ばれます。

 

93-95では、JavaScriptwindow.open()メソッドの引数に指定するオプションを生成しています。行97-101With…End Withでは、StringBuilderAppend()メソッドで以下のJavaScriptを生成しています。

 

<script language='javascript'>
window.open('PopupDelete.aspx?id=9999','_blank','features');

</script>

 

JavaScriptwindow.open()メソッドは、新規ウィンドウを開きます。Open()メソッドの引数には、urltargetfeaturesを指定します。urlには、新規ウィンドウに表示するファイルPopupDelete.aspxを指定します。?id=9999は、QueryStringと呼ばれるパラメータです。このサンプルでは、親ウィンドウから子ウィンドウにデータを渡すのにQueryStringを使用します。id=には、更新するレコードの得意先IDを指定します。

 

102では、Page.RegisterClientScriptBlock()メソッドでJavaScriptを登録します。ここで登録したJavaScriptは、Webページがロードされたときにクライアント側のブラウザから実行されます。

 

92: Sub InsertScriptBlock(intCustomerID As Integer)
 93:   Dim strFeatures As String = "height=200,width=330,left=10,top=10," & _
 94:     "location=no,menubar=no,resizable=yes,scrollbars=no,dependent=yes," & _
 95:     "status=no,titlebar=yes,toolbar=no"
 96:   Dim sbScript As New StringBuilder()
 97:   With sbScript
 98:     .Append("<script language='javascript'>" & vbCrLf)
 99:     .Append(vbTab & "window.open('PopupDelete.aspx?id=" &

intCustomerID.ToString & "','_blank','" & strFeatures & "');" & vbCrLf)
100:     .Append("</" & "script>")
101:   End With             
102:   RegisterClientScriptBlock("openWindow", sbScript.ToString)
103: End Sub

 

 

Sub InsertAlertScript()の処理

 

このサブプロシージャでは、エラーメッセージをポップアップウィンドウに表示するJavaScriptを生成して登録します。InsertAlertScriptは、CreateDataSet()関数からエラーが発生したときに呼ばれます。ここで登録したJavaScriptは、Webページがロードされたときにクライアント側のブラウザから実行されます。

 

105: Sub InsertAlertScript(strMessage As String)
106:   Dim strMsg As String = strMessage.Replace("'","\'")
107:   Dim sbScript As New StringBuilder()
108:   With sbScript
109:     .Append("<script language='javascript'>" & vbCrLf)
110:     .Append(vbTab & "alert('" & strMsg & "');" & vbCrLf)
112:     .Append("</" & "script>")
113:   End With
114:   RegisterClientScriptBlock("alertScript", sbScript.ToString)
115: End Sub

 

 

Function CreateDataSet()関数の処理

 

この関数は、DataSetを作成して返します。CreateDataSetは、BindDataGrid()から呼ばれます。

 

128-129では、Connectionのインスタンスを生成しています。Connectionの引数には、Web.Configに登録されているデータベース接続文字列を指定しています。Web.Configに登録されている内容を取得するには、ConfigurationSettingsAppSettings()メソッドを使用します。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の引数には、SQLConnectionオブジェクトを指定しています。

 

132-137Try…Catch…End Tryブロックでは、DataAdapterFill()メソッドでSQLを実行して得意先テーブルをDataSetに取り込んでいます。行132-133Tryブロックでエラーが発生したときは、行134-136Catchブロックが実行されます。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, _
127:   Optional strConnectionString As String = "conStringAccNw") As DataSet
128:   Dim con As New OleDbConnection( _
129:     ConfigurationSettings.AppSettings(strConnectionString))
130:   Dim da As New OleDbDataAdapter(strSQL, con)
131:   Dim ds As New DataSet()
132:   Try
133:     da.Fill(ds)
134:   Catch e As Exception
135:     InsertAlertScript(e.Message)
136:     Return Nothing
137:   End Try
138:   Return ds
139: End Function

 

 

リスト DataGridDelete.aspxのソースコード(コード編)

  1: <%@ Page language="vb" SmartNavigation="false" %>
  2: <%@ Import Namespace="System.Data" %>
  3: <%@ Import Namespace="System.Data.OleDb" %>
  4:
  5: <script language="vb" runat="server">
  6: Private mdt As DataTable
  7: Private mintCustomerID As Integer = 0
  9:
 10: Sub Page_Load()
 22: End Sub
 23:
 24: Sub btnRefresh_Click(s As Object, e As EventArgs)
 40: End Sub
 41:
 42: Sub dgrdCustomers_ItemCreated(s As Object, e As DataGridItemEventArgs)
 44: End Sub
 45:
 46: Sub dgrdCustomers_ItemDataBound(s As Object, e As DataGridItemEventArgs)
 56: End Sub
 57:
 58: Sub dgrdCustomers_ItemCommand(s As Object, e As DataGridCommandEventArgs)
 64: End Sub
 65:
 66: Sub ibtnDelete_Command(s As Object, e As CommandEventArgs)
 70: End Sub
 71:
 72: Sub BindDataGrid()
 90: End Sub
 91:
 92: Sub InsertScriptBlock(intCustomerID As Integer)
103: End Sub
104:
105: Sub InsertAlertScript(strMessage As String)
115: End Sub
116:
117: Function CreateDataReader(strSQL As String, _

118:   Optional strConnectionString As String = "conStringAccNw") As OleDbDataReader
124: End Function
125:
126: Function CreateDataSet(strSQL As String, _

127:   Optional strConnectionString As String = "conStringAccNw") As DataSet
139: End Function
141: </script>

 

 

◆サブプログラムPopupDelete.aspxの解説(HTML編)

 

子ウィンドウのWebフォームには、TextBoxButtonを作成しています。TextBoxには、削除される得意先レコードが表示されますので確認することができます。

 

93-104<tr>…</tr>では、得意先IDLabelTextBoxを定義しています。TextBoxには、得意先レコードの得意先IDが表示されます。TextBoxReadOnlyプロパティにTrueを設定して読み込み専用にしています。

 

後続する<tr>…</tr>では、得意先名、担当者名、部署役職、電話番号のLabelTextBoxを定義しています。

 

192-199では、「削除」と「閉じる」のボタンを定義しています。

 

リスト PopupDelete.aspxのソースコード(HTML)

78: <html>
 84: <body>
 85: <form id="frmPopupDelete" runat="server">
 92: <table>
 93: <tr>
 94: <td>
 95:   <asp:Label id="lblCustomerID" runat="server"
 97:     Text="ID" />
 98: </td>
 99: <td>
100:   <asp:TextBox id="txtCustomerID" runat="server"
102:     Columns="4" ReadOnly="True" />
103: </td>
104: </tr>
105:
106: <tr>
107: <td>
108:   <asp:Label id="lblCompanyName" runat="server"
110:     Text="
得意先名" />
111: </td>
112: <td>
113:   <asp:TextBox id="txtCompanyName" runat="server"
115:     Columns="40" ReadOnly="True" />
116: </td>
117: </tr>
    
・・・

158: </table>
192: <asp:Button id="btnDelete" runat="server"
193:   Text="
削除"
195:   OnClick="btnDelete_Click" />
196: <asp:Button id="btnClose" runat="server"
198:   Text="
閉じる"
199:   />
204: </form>
205: </body>
205: </html>

 

 

◆サブプログラムPopupDelete.aspxの解説(コード編)

 

PopupDelete.aspxは、Webフォームから削除したレコードを2段階でデータベースに反映します。Webフォームから削除したレコードは、DataTable上で削除フラグが付けられます。次に、DataTableの削除フラグが付けられたレコードをデータベースから抹消します。データベースからレコードを抹消したら、親ウィンドウをポストバックさせてDataGridをリフレッシュします。

 

Sub Page_Load()イベントの処理

 

このイベントは、ページがロードされたときに発生します。Page_Loadでは、ページの初期化処理を行います。

 

9では、Session変数に保存されている得意先テーブルのDataTableを取得して変数に退避します。

 

10-13If…EndIfでは、ページが最初にロードされたか調べています。最初にロードされたときは、「閉じる」ボタンにクライアント側で動作するonClickイベントを登録しています。onClickイベントでは、JavaScriptwindow.close()メソッドを実行して子ウィンドウを閉じます。次に、DisplayRecord()を呼び出してTextBoxに得意先レコードを表示します。

 

  8: Sub Page_Load()
  9:   mdt = CType(Session("Customers"), DataTable)
 10:   If Not IsPostBack Then
 11:     btnClose.Attributes.Add("onClick", "window.close();")
 12:     DisplayRecord()
 13:   End If
 14: End Sub

 

 

Sub btnDelete_Click()イベントの処理

 

このイベントは、削除ボタンをクリックしたときに発生します。このイベントでは、得意先テーブルのレコードを削除します。また、ここで削除したレコードを親ウィンドウのDataGridから消去します。

 

17では、DeleteRecord()関数を呼び出して得意先テーブルのレコードを削除します。DeleteRecordからは、処理の結果がメッセージで返されます。行19-29With…End Withでは、StringBuilderAppend()メソッドで以下のJavaScriptを生成しています。

 

<script language='javascript'>
window.opener.frmMain.txtMessage.value = 'message';
alert('message');  or  window.close();

</script>"

 

JavaScriptwindow.opener.frmMain.txtMessage.value=は、親ウィンドウのtxtMessage.valueにメッセージを設定します。txtMessageには、クライアント側で動作するonProperyChangeイベントが登録されていますので、このイベントが実行されます。onPropertyChangeイベントには、WebページをポストバックさせるJavaScriptが記述されていますので、WebページがポストバックされてDataGridがリフレッシュされます。

 

JavaScriptalert()関数は、「同時実行違反」のエラーが発生したときに生成されます。alert()関数は、ポップアップウィンドウにエラーメッセージを表示します。window.close()は、レコードが正常に削除されたときに生成されます。

 

30では、Page.RegisterClientScriptBlock()メソッドでJavaScriptを登録しています。ここで登録したJavaScriptは、Webページがロードされたときクライアント側のブラウザから実行されます。

 

16: Sub btnDelete_Click(s As Object, e As EventArgs)
 17:   Dim strMessage As String = DeleteRecord()
 18:   Dim sbScript As New StringBuilder()
 19:   With sbScript
 20:     .Append("<script language='javascript'>" & vbCrLf)
 21:     .Append(vbTab & "window.opener.frmMain.txtMessage.value = '" & _
 22:       strMessage & "';" & vbCrLf)
 23:     If strMessage = "
すでに削除済みです!" Then
 24:       .Append(vbTab & "alert('" & strMessage & "');" & vbCrLf)
 25:     Else
 26:       .Append(vbTab & "window.close();" & vbCrLf)
 27:     End If
 28:     .Append("</" & "script>")
 29:   End With
 30:   RegisterClientScriptBlock("delete", sbScript.ToString)
 31: End Sub

 

 

Sub DisplayRecord()の処理

 

このサブプロシージャでは、TextBoxに得意先テーブルのレコードを表示します。DisplayRecordは、Page_Loadイベントからページが最初にロードされたときに呼ばれます。

 

34では、RequestParamsコレクションからQueryStingに指定しているパラメータを取得しています。QueryStringには、親ウィンドウのDataGridから選択したレコードの得意先IDが指定されています。Request.Params()の代わりにRequest.QueryString()を使用することもできます。

 

PupupUpdate.aspx?id=9999

Request.Params("id")                     è 9999

Request.QueryString("id")             è 9999

 

35では、DataTableRowsコレクションのFind()メソッドで得意先のレコードを検索します。Find()メソッドの引数には、DataTableの主キー(得意先ID)を指定します。Find()メソッドからは、DataRowが返されます。

 

36-42If…End Ifでは、レコードが見つかったか調べています。レコードが見つかったときは、DataRowから得意先ID、得意先名、担当者名、部署役職、電話番号を取得してTextBoxに表示します。担当者名、役職部署、電話番号は、Nullの可能性があるためDataRowIsNull()メソッドで調べています。Nullのときは、空白を表示します。

 

33: Sub DisplayRecord()
 34:   Dim intCustomerID As Integer = Int32.Parse( Request.Params("id") )
 35:   Dim dr As DataRow = mdt.Rows.Find(intCustomerID)
 36:   If Not (dr Is Nothing) Then
 37:     txtCustomerID.Text = dr("CustomerID")
 38:     txtCompanyName.Text = dr("CompanyName")
 39:     txtContactName.Text = Iif(dr.IsNull("ContactName"), "", dr("ContactName"))
 40:     txtContactTitle.Text = Iif(dr.IsNull("ContactTitle"), "", dr("ContactTitle"))
 41:     txtPhone.Text = Iif(dr.IsNull("Phone"), "", dr("Phone"))
 42:   End If
 43: End Sub

 

 

Function DeleteRecord()関数の処理

 

この関数では、DataTableのレコードに削除フラグを付けて削除します。DeleteRecord()は、削除ボタンのOnClickイベントから呼ばれます。

 

50では、DataTableRowsコレクションのFind()メソッドで削除するレコードを検索しています。Find()メソッドの引数には、得意先IDを指定します。行51-56If…Else…End Ifでは、削除するレコードが見つかったか調べています。レコードが見つかったときは、DataRowDeleteメソッドでレコードに削除フラグを付けます。さらに、UpdateDataTable()関数を呼び出してデータベースからレコードを抹消します。レコードが見つからなかったときは、「すでに削除済みです!」のエラーで戻ります。

 

45: Function DeleteRecord() As String
 46:   Dim strMessage As String
 47:   Dim intCustomerID As Integer = Int32.Parse( txtCustomerID.Text )
 48:   Dim strSQL As String = "Select CustomerID From Customers"
 49:
 50:   Dim dr As DataRow = mdt.Rows.Find(intCustomerID)
 51:   If Not (dr Is Nothing) Then
 52:     dr.Delete
 53:     Return UpdateDataTable(strSQL)
 54:   Else
 55:     Return ("
すでに削除済みです!")
 56:   End If
 57: End Function

 

 

Function UpdateDataTable()関数の処理

 

この関数では、DataTableの削除フラグが付いたレコードをデータベースから抹消します。この関数は、DeleteRecord()から呼ばれます。UpdateDataTable()の引数には、strSQLstrConnectionStringを指定します。strSQLには、得意先テーブルからレコードを抽出するSQLを指定します。strConnectionStringには、データベースの接続文字列を指定します。DataTableをデータベースに反映するには、DataAdapterUpdate()メソッドを使用します。Update()メソッドで使用するINSERTUPDATEDELETESQLは、CommandBuilderで自動生成します。

 

61-62では、Connectionのインスタンスを生成しています。Connectionの引数には、データベースの接続文字列を指定します。行63では、DataAdapterのインスタンスを生成しています。DataAdapterの引数には、SQLConnectionのオブジェクトを指定します。引数のSQLには、SELECTステートメントを指定します。行64では、CommandBuilderDataTableをデータベースに反映するためのSQLを自動生成します。CommandBuilderは、SELECTステートメントを元にINSERTUPDATEDELETESQLを生成します。

 

67-72Try…Catch…End Tryブロックでは、DataAdapterUpdate()メソッドでDataTableの削除フラグが付いているレコードをデータベースから抹消します。DataTableのレコードが削除されたときは、DELETEステートメントで、データベースからレコードを抹消します。このサンプルでは、レコードが存在するときすでに変更されていても抹消します。レコードが存在しないときは、「すでに削除済みです!」のエラーとします。

 

Update()メソッドでエラーが発生したときは、行70-71Catchブロックが実行されます。行73では、戻り値として処理の結果を示すメッセージを返します。

 

「すでに削除済みです!」のエラーが発生したときは、ポップアップウィンドウにエラーメッセージを表示します。このとき、親ウィンドウのDataGridには最新のデータが表示されますので、目的のレコードは消去されます。「すでに削除済みです!」のエラーが表示されたときは、子ウィンドウの「閉じる」ボタンをクリックしてキャンセルします。

 

59: Function UpdateDataTable(strSQL As String, _
 60:   Optional strConnectionString As String = "conStringAccNw") As String
 61:   Dim con As New OleDbConnection( _
 62:     ConfigurationSettings.AppSettings(strConnectionString))
 63:   Dim da As New OleDbDataAdapter(strSQL, con)
 64:   Dim cb As New OleDbCommandBuilder(da)
 65:   Dim strMessage As String
 66:
 67:   Try
 68:     da.Update(mdt)
 69:     strMessage = "
正常終了!"
 70:   Catch
 71:     strMessage = "
すでに削除済みです!"
 72:   End Try
 73:   Return strMessage
 74: End Function

 

 

リスト PopupDelete.aspxのソースコード(コード編)

  1: <%@ Page language="vb" SmartNavigation="False" %>
  2: <%@ Import Namespace="System.Data" %>
  3: <%@ Import Namespace="System.Data.OleDb" %>
  4:
  5: <script language="vb" runat="server">
  6: Private mdt As DataTable
  7:
  8: Sub Page_Load()
 14: End Sub
 15:
 16: Sub btnDelete_Click(s As Object, e As EventArgs)
 31: End Sub
 32:
 33: Sub DisplayRecord()
 43: End Sub
 44:
 45: Function DeleteRecord() As String
 57: End Function
 58:
 59: Function UpdateDataTable(strSQL As String, _
 60:   Optional strConnectionString As String = "conStringAccNw") As String
 74: End Function
 76: </script>

 

Note

削除するレコードがすでに変更されているとき、同時実行違反とするには

 

DataAdapterSelectCommandSelect 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がデータベースに存在するときに無条件に削除されます。レコードが他のクライアントから変更されていないか確認してから削除するには、DataAdapterSelectCommandSelect * 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('削除してよろしいですか?');")

 

 

ASP.NET DataGrid2のホームへ戻る