ASP.NET + Oracle Part3 のホームへ戻る

DataAdapterRowUpdatedイベントを利用してCustomerIDを同期させる (ch58DataGrid4.aspx)

 

Customers表のCustomerIDのようにAutoNumber/Identity型の列が含まれているDataTableを、OracleDataAdapterUpdateメソッドでOracleデータベースに反映すると、データベース上のCustomerIDDataTable上のCustomerIDが不一致になります。

 

OracleデータベースのCustomers表に新規行(レコード)を追加すると、SEQUENCEからCustomerIDを取得して自動採番します。一方、DataTableに新規行を追加すると、DataTableの最終行のCustomerID+1を自動採番[1]します。このように自動採番する方式が異なりますので、新規行をOracleデータベースに反映した後、DataTableをデータベースと同期させる必要があります。

 

このサンプルは、OracleDataAdapterRowUpdatedイベントを利用して、DataTableCustomerIDをデータベースと同期させています。DataTableとデータベースを同期させるには、後述する出力パラメータを利用する方法もあります。

 

このサンプルでは、以下のノウハウを習得することができます。

 

DataTableOracleデータベースの表を同期させる方法

DataAdapterRowUpdateイベントの使い方

Oracleデータベースに表に新規行(レコード)を追加した自動採番したIDを取得する方法

DataRowの列の値を更新する方法

DataRowAcceptChangesメソッドの使い方

 

 

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)

cccHandles 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)を取得して、DataRowCustomerID列を更新します。つまり、DataTableCustomerIDCustomers表の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 = NothingDataTableNullにしていたコードをコメントにします。

 

Private Sub DataGrid1_UpdateCommand(ByVal source As Object,

cccByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)

cccHandles 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から[新規登録]をクリックして新規行(レコード)を追加すると、DataTableDataRow(レコード)を追加します。DataRowDataColumn(CustomerID)AutoIncrementプロパティにTrueが設定されていますので、CustomerIDは自動採番されます。ここでは、意図的に負の番号が採番されるようにしています。

 

Dim dr As DataRow = mdt.NewRow  ‘ CustomerIDが自動採番される

・・・

mdt.Rows.Add(dr) ‘ DataRowDataTableに追加する

 

DataTableDataRowを追加して、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表に行(レコード)を追加すると、OracleDataAdapterRowUpdatedイベントが発生します。HandleRowUpdatedイベントでは、OracleRowUpdatedEventArgsオブジェクトのStatusプロパティとStatementTypeプロパティを参照して、Customers表に行(レコード)が追加されたか調べます。行(レコード)が追加されたときは、OracleCommandオブジェクトのExecuteScalarメソッドを実行してSEQUENCEからCURRVALを取得してDataRowCustomerIDを更新します。

 

SELECT Customers_CustomerID_Seq.CURRVAL FROM DUAL;

 

Customers_CustomerID_Seq.CURRVALには、Customers表に追加した行(レコード)のCustomerIDが格納されています。DataRowCustomerIDを更新したら、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,

cccByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)

cccHandles 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

 



[1] このサンプルでは意図的に負の番号が採番されるようにしています。

ASP.NET + Oracle Part3 のホームへ戻る