DataAdapter イベントの使用

ADO.NET DataAdapter は、データ ソースのデータに対して行われた変更に応答するために使用できる 3 つのイベントを公開します。DataAdapter イベントを次の表に示します。

イベント 説明
RowUpdating 行に対する UPDATE、INSERT、または DELETE の各操作が (Update メソッドの 1 つの呼び出しによって) 開始しようとしています。
RowUpdated 行に対する UPDATE、INSERT、DELETE の各操作が (Update メソッドの 1 つの呼び出しによって) 完了しました。
FillError Fill 操作中にエラーが発生しました。

RowUpdating と RowUpdated

RowUpdating は、DataSet 側で生じた行への更新が、データ ソース側で処理される前に発生します。RowUpdated は、DataSet 側で生じた行に対する更新が、データ ソース側で処理された後で発生します。したがって、更新が始まる前に RowUpdating を使用して更新の動作を変更することで、更新発生時に行う追加の処理の提供、更新行への参照の保存、現在の更新のキャンセル、後で処理するバッチ処理のための更新スケジュールなどを提供できます。RowUpdated は、更新中に発生するエラーや例外の応答に便利です。DataSet にエラー情報や再試行ロジックなどを追加できます。

RowUpdating イベントおよび RowUpdated イベントに渡される RowUpdatingEventArgs 引数および RowUpdatedEventArgs 引数に含まれるのは、更新を実行するために使用される Command オブジェクトを参照する Command プロパティ、更新情報を格納する DataRow オブジェクトを参照する Row プロパティ、どのタイプの更新を実行するかを示す StatementType プロパティ、適用可能な場合は TableMapping、および、操作の Status を保持しています。

Status プロパティを使用すると、操作中にエラーが発生したかどうかを確認したり、必要に応じて現在の行および結果行に対するアクションを制御したりできます。イベントが発生すると、Status プロパティは Continue または ErrorsOccurred のいずれかになります。次の表では、更新の後続のアクションを制御するために Status プロパティに設定できる値を示しています。

ステータス 説明
Continue 更新操作を続行します。
ErrorsOccurred 更新操作を中止し、例外をスローします。
SkipCurrentRow 現在の行を無視し、更新操作を続行します。
SkipAllRemainingRows 更新操作を中止しますが、例外はスローしません。

Status プロパティを ErrorsOccurred に設定すると、例外がスローされます。Errors プロパティを例外として設定することで、どの例外をスローするかを制御できます。Status に対して他の値の 1 つを使用することで、例外をスローすることを防止できます。

ContinueUpdateOnError プロパティを使用して更新行に関するエラーを処理することもできます。DataAdapter.ContinueUpdateOnErrortrue に設定すると、行を更新した結果、例外がスローされようとしているときに、例外のテキストをその行の RowError 情報の中に格納し、例外をスローせずに処理を続行できます。これにより、Update が完了した時点でエラーに応答できるようになります。これに対して RowUpdated イベントを使用すると、エラーが発生した時点でエラーに応答できます。

イベント ハンドラを追加および削除する方法を次のサンプル コードに示します。RowUpdating イベント ハンドラは、削除されたすべてのレコードのログをタイムスタンプと共に記録します。RowUpdated イベント ハンドラは、DataSet の行の RowError プロパティにエラー情報を追加し、例外をスローせずに処理を続行します (ContinueUpdateOnError = true の動作を反映します)。

Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", nwindConn)

' Add handlers.
AddHandler custDA.RowUpdating, New SqlRowUpdatingEventHandler(AddressOf OnRowUpdating)
AddHandler custDA.RowUpdated, New SqlRowUpdatedEventHandler(AddressOf OnRowUpdated)

' Set DataAdapter command properties, fill the DataSet, and modify the DataSet.

custDA.Update(custDS, "Customers")

' Remove handlers.
RemoveHandler custDA.RowUpdating, New SqlRowUpdatingEventHandler(AddressOf OnRowUpdating)
RemoveHandler custDA.RowUpdated, New SqlRowUpdatedEventHandler(AddressOf OnRowUpdated)

Private Shared Sub OnRowUpdating(sender As Object, args As SqlRowUpdatingEventArgs)
  If args.StatementType = StatementType.Delete Then
    Dim tw As System.IO.TextWriter = System.IO.File.AppendText("Deletes.log")
    tw.WriteLine("{0}: Customer {1} Deleted.", DateTime.Now, args.Row("CustomerID", DataRowVersion.Original))
    tw.Close()
  End If
End Sub

Private Shared Sub OnRowUpdated(sender As Object, args As SqlRowUpdatedEventArgs)
  If args.Status = UpdateStatus.ErrorsOccurred
    args.Status = UpdateStatus.SkipCurrentRow
    args.Row.RowError = args.Errors.Message
  End If
End Sub
[C#]
SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", nwindConn);

// Add handlers.
custDA.RowUpdating += new SqlRowUpdatingEventHandler(OnRowUpdating);
custDA.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);

// Set DataAdapter command properties, fill the DataSet, and modify the DataSet.

custDA.Update(custDS, "Customers");

// Remove handlers.
custDA.RowUpdating -= new SqlRowUpdatingEventHandler(OnRowUpdating);
custDA.RowUpdated -= new SqlRowUpdatedEventHandler(OnRowUpdated);

protected static void OnRowUpdating(object sender, SqlRowUpdatingEventArgs args)
{
  if (args.StatementType == StatementType.Delete)
  {
    System.IO.TextWriter tw = System.IO.File.AppendText("Deletes.log");
    tw.WriteLine("{0}: Customer {1} Deleted.", DateTime.Now, args.Row["CustomerID", DataRowVersion.Original]);
    tw.Close();
  }
}

protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args)
{
  if (args.Status == UpdateStatus.ErrorsOccurred)
  {
    args.Row.RowError = args.Errors.Message;
    args.Status = UpdateStatus.SkipCurrentRow;
  }
}

FillError

DataAdapter は、Fill 操作中にエラーが発生すると FillError イベントを発行します。このタイプのエラーは通常、追加する行のデータを .NET Framework 型に変換したときに、有効桁を消失してしまった場合に発生します。

Fill 操作中にエラーが発生した場合、現在の行は DataTable に追加されません。FillError イベントを使用すると、エラーを解決してその行を追加するか、または除外された行を無視し、Fill 操作を続行できます。

FillError イベントに渡す FillErrorEventArgs には、エラーに応答してエラーを解決できるいくつかのプロパティを含めることができます。FillErrorEventArgs オブジェクトのプロパティを次の表に示します。

プロパティ 説明
Errors 発生した Exception
DataTable エラー発生時にデータを格納しようとしていた DataTable オブジェクト。
Values エラー発生時に追加しようとしていた行の値を保持しているオブジェクトの配列。Values 配列の序数参照は、追加しようとしていた行の列の序数参照に対応します。たとえば、Values[0] は、行の第 1 列として追加しようとした値です。
Continue Exception をスローするかどうかを選択できます。Continue プロパティを false に設定すると、エラーが発生した時に現在の Fill 操作を終了し、例外をスローします。Continuetrue に設定すると、エラーに関係なく Fill 操作が続行します。

次に示すのは、DataAdapterFillError イベントのイベント ハンドラを追加するサンプル コードです。この FillError イベント コードの例は、有効桁の消失が発生したかどうかを確認し、例外に応答する機会を与えます。

AddHandler myDA.FillError, New FillErrorEventHandler(AddressOf FillError)

Dim myDS As DataSet = New DataSet
myDA.Fill(myDS, "MyTable")

Private Shared Sub FillError(sender As Object, args As FillErrorEventArgs)
  If args.Errors.GetType() Is Type.GetType("System.OverflowException") Then
    ' Code to handle precision loss.
    ' Add a row to table using the values from the first two columns.
    DataRow myRow = args.DataTable.Rows.Add(New Object() {args.Values(0), args.Values(1), DBNull.Value})
    ' Set the RowError containing the value for the third column.
    args.RowError = "OverflowException Encountered. Value from data source: " & args.Values(2)

    args.Continue = True
  End If
End Sub
[C#]
myDA.FillError += new FillErrorEventHandler(FillError);

DataSet myDS = new DataSet();
myDA.Fill(myDS, "MyTable");

protected static void FillError(object sender, FillErrorEventArgs args)
{
  if (args.Errors.GetType() == typeof(System.OverflowException))
  {
    // Code to handle precision loss.
    //Add a row to table using the values from the first two columns.
    DataRow myRow = args.DataTable.Rows.Add(new object[] {args.Values[0], args.Values[1], DBNull.Value});
    //Set the RowError containing the value for the third column.
    args.RowError = "OverflowException Encountered. Value from data source: " + args.Values[2];

    args.Continue = true;
  }
}

参照

.NET Framework データ プロバイダによるデータのアクセス | SqlRowUpdatedEventArgs クラス | SqlRowUpdatingEventArgs クラス | OleDbRowUpdatedEventArgs クラス | OleDbRowUpdatingEventArgs クラス | OdbcRowUpdatedEventArgs クラス | OdbcRowUpdatingEventArgs クラス | FillErrorEventArgs クラス