Actualizar orígenes de datos con DataAdapters (ADO.NET)

Actualización: November 2007

El método Update de DataAdapter se llama para reflejar en el origen de datos todos los cambios efectuados en DataSet. El método Update, al igual que el método Fill, acepta como argumentos una instancia de DataSet y, de forma opcional, un objeto DataTable o un nombre de DataTable. La instancia de DataSet es el DataSet que contiene los cambios efectuados, y DataTable identifica la tabla desde la que se pueden recuperar esos cambios. Si no se especifica DataTable, se utiliza el primer DataTable de DataSet.

Al llamar al método Update, DataAdapter analiza los cambios efectuados y ejecuta el comando apropiado (INSERT, UPDATE o DELETE). Cuando DataAdapter encuentra un cambio en DataRow, utiliza los comandos InsertCommand, UpdateCommand o DeleteCommand para reflejarlo. De esta forma, se obtiene el máximo rendimiento de la aplicación de ADO.NET al especificar la sintaxis del comando en la fase de diseño y utilizar, siempre que es posible, procedimientos almacenados. Antes de llamar a Update deben establecerse de forma explícita los comandos. Si se llama a Update y el comando correspondiente a una actualización determinada no existe (por ejemplo, no hay un comando DeleteCommand para las filas eliminadas), se inicia una excepción.

Nota:

Si está utilizando procedimientos almacenados de SQL Server para editar o eliminar datos con DataAdapter, asegúrese de que no utiliza SET NOCOUNT ON en la definición del procedimiento almacenado. Esto hace que el recuento de filas afectadas vuelva a cero, lo que DataAdapter interpreta como un conflicto de concurrencia. En este evento, se iniciará una DBConcurrencyException.

Se pueden usar los parámetros de comando para especificar los valores de entrada y salida de una instrucción SQL o un procedimiento almacenado para cada fila modificada en DataSet. Para obtener más información, vea Parámetros DataAdapter (ADO.NET).

Nota:

Es importante comprender la diferencia entre eliminar una fila de una DataTable y quitar la fila. Al llamar al método Remove o RemoveAt, la fila se quita inmediatamente. Cualquier fila correspondiente en el origen de datos back end no se verá afectada si a continuación se pasa DataTable o DataSet a DataAdapter y se llama a Update. Al utilizar el método Delete, la fila permanece en DataTable y se marca para eliminación. Si a continuación se pasa DataTable o DataSet a DataAdapter y se llama a Update, la fila correspondiente en el origen de datos back end se elimina.

Si DataTable está asignada a una única base de datos o se ha generado a partir de ella, puede utilizar el objeto DbCommandBuilder para generar automáticamente los objetos DeleteCommand, InsertCommand y UpdateCommand de DataAdapter. Para obtener más información, vea Generar comandos con objetos CommandBuilder (ADO.NET).

Utilizar UpdatedRowSource para asignar valores a DataSet

Puede controlar la forma en que los valores devueltos desde el origen de datos se asignan a DataTable después de una llamada al método Update de DataAdapter, utilizando la propiedad UpdatedRowSource de un objeto DbCommand. Al asignar la propiedad UpdatedRowSource a uno de los valores de enumeración UpdateRowSource, puede determinar si los parámetros que devuelven los comandos DataAdapter se deben omitir o se deben aplicar a la fila cambiada en DataSet. También puede especificar si la primera fila devuelta (si existe) se aplica a la fila modificada en DataTable.

En la tabla siguiente se describen los distintos valores de la enumeración UpdateRowSource y la forma en que afectan al comportamiento del comando utilizado con DataAdapter.

Enumeración UpdatedRowSource

Descripción

Both

Tanto los parámetros de salida como la primera fila del conjunto de resultados devuelto se pueden asignar a la fila modificada en DataSet.

FirstReturnedRecord

Sólo los datos de la primera fila del conjunto de resultados devuelto se pueden asignar a la fila modificada en el DataSet.

None

Se pasan por alto todos los parámetros de salida y las filas del conjunto de resultados devuelto.

OutputParameters

Sólo los parámetros de salida se pueden asignar a la fila modificada en DataSet.

El método Update vuelve a resolver los cambios en el origen de datos; sin embargo, puede que otros clientes hayan modificado datos en el origen de datos desde la última vez que se llenó DataSet. Para actualizar DataSet con datos actuales, utilice el DataAdapter y el método Fill. De esta forma se agregan las filas nuevas a la tabla y se actualiza la información en las filas ya existentes. El método Fill determina si se va a agregar una nueva fila o si se va a actualizar una fila existente mediante el examen de los valores de clave principal de las filas de DataSet y las filas devueltas por SelectCommand. Si el método Fill encuentra un valor de clave principal de una fila de DataSet que coincide con un valor de clave principal de una fila de los resultados devueltos por SelectCommand, éste actualiza la fila existente con la información de la fila devuelta por SelectCommand y establece el RowState de la fila existente en Unchanged. Si una fila devuelta por SelectCommand tiene un valor de clave principal que no coincide con ninguno de los valores de clave principal de las filas de DataSet, el método Fill agrega una nueva fila con un RowState de Unchanged.

Nota:

Si SelectCommand devuelve los resultados de una combinación externa (OUTER JOIN), DataAdapter no establecerá un valor PrimaryKey para la tabla DataTable resultante. Debe definir PrimaryKey para asegurarse de que las filas duplicadas se resuelven correctamente. Para obtener más información, vea Definir claves principales (ADO.NET).

Para controlar las excepciones que se puedan producir al llamar al método Update, se puede utilizar el evento RowUpdated para responder a los errores de actualización de filas en cuanto se producen (vea Control de eventos DataAdapter (ADO.NET)), o bien se puede establecer DataAdapter.ContinueUpdateOnError en true antes de llamar a Update y responder a la información de error almacenada en la propiedad RowError de una determinada fila una vez completada la actualización (vea Información de errores de fila).

Nota   Llamar a AcceptChanges en DataSet, DataTable o DataRow hará que todos los valores Original de DataRow se sobrescriban con los valores Current de DataRow. Si se han modificado los valores de campo que identifican de forma única a una fila, los valores Original dejarán de coincidir con los valores del origen de datos después de llamar a AcceptChanges. Se llama automáticamente a AcceptChanges para cada fila durante una llamada al método Update de DataAdapter. Puede conservar los valores originales durante una llamada al método Update estableciendo primero la propiedad AcceptChangesDuringUpdate de DataAdapter en false o creando un controlador de eventos para el evento RowUpdated y estableciendo Status en SkipCurrentRow. Para obtener más información, vea Combinar contenido de DataSet (ADO.NET) y Control de eventos DataAdapter (ADO.NET).

Ejemplo

Los ejemplos siguientes muestran cómo realizar las actualizaciones en las filas modificadas estableciendo de forma explícita UpdateCommand de DataAdapter y llamando a su método Update . Observe cómo el parámetro especificado en la cláusula WHERE de la instrucción UPDATE tiene el valor adecuado para usar el valor Original de SourceColumn. Este hecho es muy importante ya que el valor Current puede haber sido modificado de forma que ya no coincida con el valor del origen de datos. El valor Original es el que se usó para rellenar la tabla DataTable a partir del origen de datos.

Private Sub AdapterUpdate(ByVal connectionString As String)

    Using connection As SqlConnection = New SqlConnection( _
       connectionString)

        Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
          "SELECT CategoryID, CategoryName FROM dbo.Categories", _
          connection)

        adapter.UpdateCommand = New SqlCommand( _
          "UPDATE Categories SET CategoryName = @CategoryName " & _
           "WHERE CategoryID = @CategoryID", connection)

        adapter.UpdateCommand.Parameters.Add( _
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")

        Dim parameter As SqlParameter = _
           adapter.UpdateCommand.Parameters.Add( _
           "@CategoryID", SqlDbType.Int)
        parameter.SourceColumn = "CategoryID"
        parameter.SourceVersion = DataRowVersion.Original

        Dim categoryTable As New DataTable
        adapter.Fill(categoryTable)

        Dim categoryRow As DataRow = categoryTable.Rows(0)
        categoryRow("CategoryName") = "New Beverages"

        adapter.Update(categoryTable)

        Console.WriteLine("Rows after update.")
        Dim row As DataRow
        For Each row In categoryTable.Rows
            Console.WriteLine("{0}: {1}", row(0), row(1))
        Next
    End Using
End Sub
private static void AdapterUpdate(string connectionString)
{
    using (SqlConnection connection =
               new SqlConnection(connectionString))
    {
        SqlDataAdapter dataAdpater = new SqlDataAdapter(
          "SELECT CategoryID, CategoryName FROM Categories",
          connection);

        dataAdpater.UpdateCommand = new SqlCommand(
           "UPDATE Categories SET CategoryName = @CategoryName " +
           "WHERE CategoryID = @CategoryID", connection);

        dataAdpater.UpdateCommand.Parameters.Add(
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

        SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(
          "@CategoryID", SqlDbType.Int);
        parameter.SourceColumn = "CategoryID";
        parameter.SourceVersion = DataRowVersion.Original;

        DataTable categoryTable = new DataTable();
        dataAdpater.Fill(categoryTable);

        DataRow categoryRow = categoryTable.Rows[0];
        categoryRow["CategoryName"] = "New Beverages";

        dataAdpater.Update(categoryTable);

        Console.WriteLine("Rows after update.");
        foreach (DataRow row in categoryTable.Rows)
        {
            {
                Console.WriteLine("{0}: {1}", row[0], row[1]);
            }
        }
    }
}

Columnas AutoIncrement

Si las tablas del origen de datos tienen columnas con incremento automático, puede rellenar las columnas de DataSet devolviendo el valor de incremento automático como un parámetro de salida de un procedimiento almacenado y asignándolo a una columna de la tabla, o devolviendo el valor de incremento automático de la primera fila de un conjunto de resultados devuelto por un procedimiento almacenado o una instrucción SQL, o mediante el evento RowUpdated de DataAdapter para ejecutar una instrucción SELECT adicional. Para obtener más información y un ejemplo, vea Recuperar valores de identidad o valores Autonuméricos (ADO.NET).

Orden de las inserciones, actualizaciones y eliminaciones

En algunas circunstancias, es importante el orden en que se envían al origen de datos los cambios realizados en el DataSet. Por ejemplo, si se actualiza el valor de una clave principal de una fila existente y se ha agregado una nueva fila con el nuevo valor de la clave principal como una clave externa, es importante que la actualización de la fila se procese antes que la inserción.

Puede usar el método Select de DataTable para devolver una matriz DataRow que sólo haga referencia a filas con un estado RowState determinado. A continuación, puede pasar la matriz DataRow al método Update de DataAdapter para procesar las filas modificadas. Al especificar un subconjunto de filas que modificar, puede controlar el orden en que se procesan las inserciones, actualizaciones y eliminaciones.

Ejemplo

Por ejemplo, en el código siguiente se garantiza que en primer lugar se realizan en la tabla las eliminaciones de filas, después las actualizaciones y finalmente las inserciones.

Dim table As DataTable = dataSet.Tables("Customers")

' First process deletes.
dataSet.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Deleted))

' Next process updates.
adapter.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.ModifiedCurrent))

' Finally, process inserts.
dataAdpater.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Added))
DataTable table = dataSet.Tables["Customers"];

// First process deletes.
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));

// Next process updates.
adapter.Update(table.Select(null, null, 
  DataViewRowState.ModifiedCurrent));

// Finally, process inserts.
adapter.Update(table.Select(null, null, DataViewRowState.Added));

Vea también

Conceptos

Estados de fila y versiones de fila

AcceptChanges y RejectChanges

Combinar contenido de DataSet (ADO.NET)

Recuperar valores de identidad o valores Autonuméricos (ADO.NET)

Otros recursos

DataAdapters y DataReaders (ADO.NET)