ADO.NET DataAdapter 公开了三个可用于响应对数据源中的数据所作更改的事件。下表显示了这些 DataAdapter 事件。

事件 说明
RowUpdating 将要开始对某行执行 UPDATE、INSERT 或 DELETE 操作(通过调用 Update 方法之一)。
RowUpdated 对某行的 UPDATE、INSERT 或 DELETE 操作(通过调用 Update 方法之一)已完成。
FillError Fill 操作过程中出错。

RowUpdating 和 RowUpdated

在数据源中处理对 DataSet 中某行的任何更新之前,将引发 RowUpdating。在数据源中处理对 DataSet 中某行的任何更新之后,将引发 RowUpdated。因此,可以使用 RowUpdating 在更新行为发生之前对其进行修改,在更新将发生时提供附加的处理,保留对已更新行的引用,取消当前更新操作并将其安排在以后进行批处理,等等。RowUpdated 用于响应在更新过程中发生的错误和异常。您可以向 DataSet 以及重试逻辑等添加错误信息。

RowUpdatingRowUpdated 事件传递的 RowUpdatingEventArgsRowUpdatedEventArgs 参数包括:Command 属性,它引用用来执行更新的 Command 对象;Row 属性,它引用包含更新信息的 DataRow 对象;StatementType 属性,它指示所执行的更新类型;TableMapping(如果适用);以及操作的 Status

可以使用 Status 属性来确定该操作过程中是否出错,如果需要,还可以控制对当前和结果行执行的操作。当该事件发生时,Status 属性将等于 ContinueErrorsOccurred。下表显示为了控制更新过程中的后继操作,可以将 Status 属性设置为的值。

状态 说明
Continue 继续执行更新操作。
ErrorsOccurred 中止更新操作并引发异常。
SkipCurrentRow 忽略当前行并继续执行更新操作。
SkipAllRemainingRows 中止更新操作但不引发异常。

如果将 Status 属性设置为 ErrorsOccurred,则将引发异常。您可以通过将 Errors 属性设置为预期异常来控制所引发的异常。如果使用其他 Status 值之一,则将防止引发异常。

也可以使用 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

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

Fill 操作过程中出错时,DataAdapter 将发出 FillError 事件。此类型的错误通常是以下情况之一导致的:

如果在 Fill 操作过程中出错,则当前行将不会被添加到 DataTable 中。FillError 事件使您能够解决错误并添加当前行,或者忽略已排除的行并继续执行 Fill 操作。

FillError 事件传递的 FillErrorEventArgs 可以包含几项可用于响应和解决错误的属性。下表显示了 FillErrorEventArgs 对象的属性。

属性 说明
Errors 已发生的 Exception
DataTable 出错时所填充的 DataTable 对象。
Values 一个对象数组,它包含出错时所添加的行的值。Values 数组的序号引用对应于所添加的行的列的序号引用。例如,Values[0] 是作为当前行的第一列添加的值。
Continue 用于选择是否引发 Exception。如果将 Continue 属性设置为 false,则将中止当前 Fill 操作并引发异常。如果将 Continue 设置为 true,那么即使出错,仍将继续执行 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

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;
  }
}