Trabajar con eventos DataAdapter

DataAdapter de ADO.NET expone tres eventos que se pueden utilizar para responder a los cambios efectuados en los datos del origen de datos. En la tabla siguiente se muestran los eventos de DataAdapter.

Evento Descripción
RowUpdating Está a punto de comenzar una operación UPDATE, INSERT o DELETE en una fila (mediante una llamada a uno de los métodos Update).
RowUpdated Se ha completado una operación UPDATE, INSERT o DELETE en una fila (mediante una llamada a uno de los métodos Update).
FillError Se ha producido un error durante una operación Fill.

RowUpdating y RowUpdated

El evento RowUpdating se activa antes de que se produzca la actualización de una fila del DataSet en el origen de datos. El evento RowUpdated se activa después de producirse la actualización de una fila del DataSet en el origen de datos. Por lo tanto, puede usar RowUpdating para modificar el comportamiento de la actualización antes de que tenga lugar, para proporcionar un control adicional del proceso durante la actualización, conservar una referencia a la fila actualizada, cancelar la actualización actual y programarla como parte de un proceso por lotes que se ejecutará después, entre otras acciones. RowUpdated es útil para reaccionar cuando se producen errores y excepciones durante la actualización. Puede agregar información de errores al DataSet, así como procedimientos de reintento, etcétera.

Entre los argumentos RowUpdatingEventArgs y RowUpdatedEventArgs que se pasan a los eventos RowUpdating y RowUpdated se incluyen los siguientes: una propiedad Command que hace referencia al objeto Command utilizado para realizar la actualización, una propiedad Row que hace referencia al objeto DataRow que contiene la información actualizada, una propiedad StatementType que indica el tipo de actualización realizada, TableMapping, si es aplicable, y el valor de Status de la operación.

Puede usar la propiedad Status para determinar si se ha producido o no un error durante la operación y, si así se desea, controlar las acciones que se emprenden con las filas actuales y las resultantes de la operación. Cuando se produce el evento, la propiedad Status toma el valor Continue o ErrorsOccurred. En la tabla siguiente se muestran los valores que se pueden asignar a la propiedad Status para controlar las acciones siguientes en el proceso de actualización.

Status Descripción
Continue Continuar la operación de actualización.
ErrorsOccurred Cancelar la operación de actualización e iniciar una excepción.
SkipCurrentRow Omitir la fila actual y continuar la operación de actualización.
SkipAllRemainingRows Cancelar la operación de actualización sin iniciar ninguna excepción.

Al asignar a la propiedad Status el valor ErrorsOccurred se inicia una excepción. Puede controlar qué excepciones se inician si establece el valor correspondiente a la excepción deseada en la propiedad Errors. El uso de un valor distinto para la propiedad Status evita que se inicie una excepción.

También puede usar la propiedad ContinueUpdateOnError para controlar los errores producidos por las filas actualizadas. Cuando DataAdapter.ContinueUpdateOnError tiene el valor true y la actualización de una fila inicia una excepción, el texto de la excepción se coloca en la información RowError de la fila en cuestión y el proceso continúa sin que se inicie ninguna excepción. De esta forma, puede reaccionar frente a errores cuando finalice el proceso Update, a diferencia del evento RowUpdated que permite reaccionar frente a los errores cuando se detectan.

En el ejemplo de código siguiente se muestra cómo se pueden agregar y quitar controladores de eventos. El controlador de eventos RowUpdating mantiene un registro con todos los registros eliminados y una marca de tiempo asociada a cada uno de ellos. El controlador de eventos RowUpdated agrega información de error a la propiedad RowError de la fila correspondiente en el DataSet, evita que se inicie la excepción y deja continuar el proceso (al igual que si 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 emite el evento FillError cuando se produce un error durante una operación de llenado (Fill). Este tipo de error suele producirse si al convertir los datos de la fila que se agrega a un tipo de .NET Framework se produce una pérdida de precisión.

Si el error se produce durante una operación Fill, la fila actual no se agrega a DataTable. El evento FillError permite resolver el error y agregar la fila, o pasar por alto la fila excluida y continuar con la operación Fill.

El objeto FillErrorEventArgs que se pasa al evento FillError puede contener varias propiedades que permiten reaccionar en caso de errores y resolverlos. En la tabla siguiente se muestran las propiedades del objeto FillErrorEventArgs.

Propiedad Descripción
Errors Excepción producida.
DataTable Objeto DataTable que se estaba llenando cuando ocurrió el error.
Values Matriz de objetos que contiene los valores de la fila que se está agregando cuando se produce el error. Las referencias de orden de la matriz Values coinciden con las de las columnas de la fila que se estaba agregando. Por ejemplo, Values[0] es el valor que se agrega en la primera columna de la fila.
Continue Permite elegir si desea iniciar una excepción (Exception) o no. Si asigna a la propiedad Continue el valor false, la operación Fill en curso se detiene y se inicia una excepción. Si a la propiedad Continue se le asigna el valor true, la operación Fill continúa pese al error.

En el ejemplo de código siguiente se agrega un controlador de eventos para el evento FillError de DataAdapter. En el código del evento FillError, el ejemplo determina si hay una posible pérdida de precisión y ofrece la posibilidad de reaccionar en ese caso.

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

Vea también

Utilizar proveedores de datos de .NET Framework para obtener acceso a datos | SqlRowUpdatedEventArgs (Clase) | SqlRowUpdatingEventArgs (Clase) | OleDbRowUpdatedEventArgs (Clase) | OleDbRowUpdatingEventArgs (Clase) | OdbcRowUpdatedEventArgs (Clase) | OdbcRowUpdatingEventArgs (Clase) | FillErrorEventArgs (Clase)