●DataAdapterのRowUpdatedイベントを利用してCustomerIDを同期させる (ch58DataGrid4.aspx)
Customers表のCustomerIDのようにAutoNumber/Identity型の列が含まれているDataTableを、OracleDataAdapterのUpdateメソッドでOracleデータベースに反映すると、データベース上のCustomerIDとDataTable上のCustomerIDが不一致になります。
OracleデータベースのCustomers表に新規行(レコード)を追加すると、SEQUENCEからCustomerIDを取得して自動採番します。一方、DataTableに新規行を追加すると、DataTableの最終行のCustomerID+1を自動採番[1]します。このように自動採番する方式が異なりますので、新規行をOracleデータベースに反映した後、DataTableをデータベースと同期させる必要があります。
このサンプルは、OracleDataAdapterのRowUpdatedイベントを利用して、DataTableのCustomerIDをデータベースと同期させています。DataTableとデータベースを同期させるには、後述する出力パラメータを利用する方法もあります。
このサンプルでは、以下のノウハウを習得することができます。
▼DataTableとOracleデータベースの表を同期させる方法
▼DataAdapterのRowUpdateイベントの使い方
▼Oracleデータベースに表に新規行(レコード)を追加した自動採番したIDを取得する方法
▼DataRowの列の値を更新する方法
▼DataRowのAcceptChangesメソッドの使い方
1. モジュールレベルの変数書き換え
ch58DataGrid1.aspxのコードビューを表示したら、Sub Page_Loadイベントの直前の変数を以下のように書き換えます。
Private mcon As OracleConnection
Private mcb As OracleCommandBuilder
Private mda As OracleDataAdapter
Private mdt As DataTable
Private
mcmdRefresh As OracleCommand
Private
Const mCacheKey = "Ch58DataGrid4DataTable"
2. Page_Loadイベントの書き換え
Page_Loadイベントを以下のように書き換えます。OracleDataAdapterのインスタンスを生成したら、RowUpdatedイベントを登録します。
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
Dim strSQL As String = "SELECT * FROM Customers " & _
"WHERE CustomerID > 40 " & _
"ORDER BY CustomerID"
mcon = New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))
mda = New OracleDataAdapter(strSQL, mcon)
mda.InsertCommand = CreateInsertCommand()
mda.UpdateCommand = CreateUpdateCommand()
mda.DeleteCommand = CreateDeleteCommand()
strSQL = "SELECT
Customers_CustomerID_Seq.CURRVAL FROM DUAL;"
mcmdRefresh = New OracleCommand(strSQL,
mcon)
AddHandler mda.RowUpdated, AddressOf
HandleRowUpdated
If Not IsPostBack Then
BindGrid()
Else
mdt = CType(Session(mCacheKey), DataTable)
End If
End Sub
3. RowUpdatedイベントを追加
クラスモジュールの最後にSub HandleRowUpdateイベントを追加します。このイベントでは、OracleデータベースのSEQUENCEからカレントのシーケンス(CustomerID)を取得して、DataRowのCustomerID列を更新します。つまり、DataTableのCustomerIDとCustomers表のCustomerIDを同期させます。
Sub HandleRowUpdated(ByVal s As Object, ByVal e As OracleRowUpdatedEventArgs)
If e.Status = UpdateStatus.Continue AndAlso _
e.StatementType = StatementType.Insert Then
e.Row("CustomerID") = CInt(mcmdRefresh.ExecuteScalar)
e.Row.AcceptChanges()
End If
End Sub
4. UpdateCommandイベントの書き換え
DataGrid1_UpdateCommandイベントを以下のように書き換えます。Oracleデータベースに新規行(レコード)を反映した後に、mdt = NothingでDataTableをNullにしていたコードをコメントにします。
Private Sub DataGrid1_UpdateCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
Handles DataGrid1.UpdateCommand
Dim strCompanyName As String = CType(e.Item.Cells(1).Controls(0), TextBox).Text
Dim strContactName As String = CType(e.Item.Cells(2).Controls(0), TextBox).Text
Dim strPhone As String = CType(e.Item.Cells(3).Controls(0), TextBox).Text
If Me.AddingNew Then
InsertRecord(strCompanyName, strContactName, strPhone)
Else
Dim intCustomerID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex)
UpdateRecord(strCompanyName, strContactName, strPhone, intCustomerID)
End If
Me.AddingNew = False
DataGrid1.EditItemIndex = -1
' mdt = Nothing コメントにする
BindGrid()
End Sub
■解説
DataGridから[新規登録]をクリックして新規行(レコード)を追加すると、DataTableにDataRow(レコード)を追加します。DataRowのDataColumn(CustomerID)のAutoIncrementプロパティにTrueが設定されていますので、CustomerIDは自動採番されます。ここでは、意図的に負の番号が採番されるようにしています。
Dim dr As DataRow = mdt.NewRow ‘ CustomerIDが自動採番される
・・・
mdt.Rows.Add(dr) ‘ DataRowをDataTableに追加する
DataTableにDataRowを追加して、OracleDataAdapterオブジェクトのUpdateメソッドを実行するとDataTableに追加した行(レコード)をOracleデータベースのCustomers表に反映します。Customers表にトリガーが設定されていますので、CustomerIDが自動採番されます。
Dim dr As DataRow = mdt.Rows(mdt.Rows.Count - 1) ‘ 追加したレコードのDataRowを取得
dr("CompanyName") = strCompanyName
dr("ContactName") = strContactName
dr("Phone") = strPhone
Try
mda.Update(mdt)
intRetValue = 1
Catch ex As Exception
Response.Write(ex.Message.ToString)
End Try
OracleデータベースのCustomers表に行(レコード)を追加すると、OracleDataAdapterのRowUpdatedイベントが発生します。HandleRowUpdatedイベントでは、OracleRowUpdatedEventArgsオブジェクトのStatusプロパティとStatementTypeプロパティを参照して、Customers表に行(レコード)が追加されたか調べます。行(レコード)が追加されたときは、OracleCommandオブジェクトのExecuteScalarメソッドを実行してSEQUENCEからCURRVALを取得してDataRowのCustomerIDを更新します。
SELECT Customers_CustomerID_Seq.CURRVAL FROM DUAL;
Customers_CustomerID_Seq.CURRVALには、Customers表に追加した行(レコード)のCustomerIDが格納されています。DataRowのCustomerIDを更新したら、DataRowオブジェクトのAcceptChangesメソッドを実行して更新を確定します。
Sub HandleRowUpdated(ByVal s As Object, ByVal e As OracleRowUpdatedEventArgs)
If e.Status = UpdateStatus.Continue AndAlso _
e.StatementType = StatementType.Insert Then
e.Row("CustomerID") = CInt(mcmdRefresh.ExecuteScalar)
e.Row.AcceptChanges()
End If
End Sub
このサンプルは、DataTableとデータベースのCustomers表を同期させていますので、DataGridから新規行(レコード)を追加してもDataTableを無効にしてリフレッシュする必要がありません。
Private Sub DataGrid1_UpdateCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
Handles DataGrid1.UpdateCommand
Dim strCompanyName As String = CType(e.Item.Cells(1).Controls(0), TextBox).Text
Dim strContactName As String = CType(e.Item.Cells(2).Controls(0), TextBox).Text
Dim strPhone As String = CType(e.Item.Cells(3).Controls(0), TextBox).Text
If Me.AddingNew Then
InsertRecord(strCompanyName, strContactName, strPhone)
Else
Dim intCustomerID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex)
UpdateRecord(strCompanyName, strContactName, strPhone, intCustomerID)
End If
Me.AddingNew = False
DataGrid1.EditItemIndex = -1
' mdt = Nothing このコードが不要になる
BindGrid()
End Sub