Personas que lo han encontrado til: 4 de 4 - Valorar este tema En un entorno multiusuario existen dos modelos para actualizar datos en una base de datos: concurrencia optimista y concurrencia pesimista. El objeto DataSet est diseado para fomentar el uso de la concurrencia optimista en actividades cuya ejecucin tiene una larga duracin, como cuando se trabaja con interaccin remota y cuando los usuarios interactan con datos. La concurrencia pesimista implica bloquear filas en el origen de datos para impedir que otros usuarios modifiquen los datos de tal forma que el usuario actual resulte afectado. En un modelo pesimista, cuando un usuario realiza una accin que hace que se aplique un bloqueo, otros usuarios no pueden realizar acciones que entraran en conflicto con el bloqueo hasta que el propietario del bloqueo lo libere. Este modelo se utiliza principalmente en aquellos entornos en los que hay mucha contencin de datos, de manera que el costo de proteger los datos con bloqueos es menor que el costo de deshacer transacciones si se producen conflictos de concurrencia. Por tanto, en un modelo de concurrencia pesimista, un usuario que actualiza una fila establece un bloqueo. Hasta que el usuario no haya terminado la actualizacin y liberado el bloqueo, nadie ms podr modificar dicha fila. Por este motivo, la concurrencia pesimista resulta ms adecuada cuando los tiempos de bloqueo son cortos, como ocurre en el procesamiento de registros mediante programacin. La concurrencia pesimista no es una opcin escalable cuando los usuarios interactan con los datos y hacen que los registros queden bloqueados durante perodos de tiempo relativamente largos. Por el contrario, los usuarios que utilizan la concurrencia optimista no bloquean una fila cuando la leen. Cuando un usuario desea actualizar una fila, la aplicacin debe determinar si otro usuario la ha modificado o no desde que se ley. La concurrencia optimista suele utilizarse en entornos con poca contencin de datos. Esto mejora el rendimiento porque no es necesario bloquear registros, a la vez que el bloqueo de registros requiere recursos adicionales del servidor. Adems, para mantener bloqueos de registros es necesaria una conexin persistente con el servidor de base de datos. Como ste no es el caso en un modelo de concurrencia optimista, las conexiones con el servidor pueden atender a un mayor nmero de clientes en menos tiempo.
En un modelo de concurrencia optimista, se considera que ha habido una infraccin si, despus de que un usuario recibe un valor de la base de datos, otro usuario modifica el valor antes de que el primer usuario haya intentado modificarlo. En el ejemplo siguiente se describe cmo el servidor resuelve una violacin de concurrencia . Las siguientes tablas muestran un ejemplo de concurrencia optimista. A la 1:00 p.m., el Usuario1 lee una fila de la base de datos con los valores siguientes: IdCliente 101 Apellido Nombre Cris Valor original Valor actual Valor en la base de datos 101 101 101 Martnez Martnez Martnez Cris Cris Cris
Martnez
A la 1:01 p.m., el Usuario2 lee la misma fila. A la 1:03 p.m., el Usuario2 cambia Nombre de "Cris" a "Cristina" y actualiza la base de datos. Nombre de columna IdCliente Apellido Nombre Valor original Valor actual Valor en la base de datos 101 101 101 Martnez Martnez Martnez Cris Cristina Cris
La actualizacin se realiza correctamente porque los valores contenidos en la base de datos en el momento de la actualizacin coinciden con los valores originales que tiene el Usuario2. A la 1:05 p.m., el Usuario1 cambia el nombre de "Cris" a "Jaime" e intenta actualizar la fila. Nombre de columna IdCliente Apellido Nombre Valor original Valor actual Valor en la base de datos 101 101 101 Martnez Martnez Martnez Cris Jaime Cristina
En este momento, el Usuario1 encuentra una infraccin de la concurrencia optimista porque los valores de la base de datos ("Jaime") ya no coinciden con los valores originales que esperaba el Usuario1 ("Cris"). Ahora hay que tomar la decisin de sobrescribir los cambios
realizados por el Usuario2 con los efectuados por el Usuario1 o cancelar los cambios del Usuario1.
Para probar si hay alguna infraccin relacionada con la concurrencia optimista al actualizar una fila de Tabla1, se utilizara la siguiente instruccin UPDATE:
UPDATE Table1 Set Col1 = @NewCol1Value, Set Col2 = @NewCol2Value, Set Col3 = @NewCol3Value WHERE Col1 = @OldCol1Value AND Col2 = @OldCol2Value AND Col3 = @OldCol3Value
La actualizacin se realizar siempre y cuando los valores originales coincidan con los valores de la base de datos. Si se ha modificado algn valor, la actualizacin no modificar la fila porque la clusula WHERE no encontrar ninguna coincidencia. Se recomienda devolver siempre un valor de clave principal nico en la consulta. De lo contrario, la instruccin UPDATE anterior puede actualizar ms de una fila, lo que quizs no sea su intencin.
Si una columna del origen de datos admite valores nulos, quizs sea necesario extender la clusula WHERE para comprobar si hay alguna referencia nula coincidente en la tabla local y en el origen de datos. Por ejemplo, la siguiente instruccin UPDATE comprueba que una referencia nula de la fila local sigue coincidiendo con una referencia nula del origen de datos o que el valor de la fila local sigue coincidiendo con el valor del origen de datos.
UPDATE Table1 Set Col1 = @NewVal1 WHERE (@OldVal1 IS NULL AND Col1 IS NULL) OR Col1 = @OldVal1
Tambin se puede decidir la aplicacin de criterios menos restrictivos al utilizar un modelo de concurrencia optimista. Por ejemplo, si slo se utilizan las columnas de clave principal en la clusula WHERE se sobrescribirn los datos, independientemente de que las otras columnas se hayan actualizado o no desde la ltima consulta. Tambin se puede aplicar una clusula WHERE slo a determinadas columnas, lo que har que se sobrescriban los datos a menos que se hayan actualizado ciertos campos desde que se consultaron por ltima vez.
Evento DataAdapter.RowUpdated
El evento RowUpdated del objeto DataAdapter puede utilizarse junto con las tcnicas descritas anteriormente para informar a la aplicacin de las infracciones de la concurrencia optimista. RowUpdated se produce despus de cada intento de actualizar una fila Modified de un DataSet. Esto permite agregar cdigo especial de control, incluyendo el procesamiento cuando se produce una excepcin, agregar informacin de error personalizada, agregar lgica de reintento, etc. El objeto RowUpdatedEventArgs devuelve una propiedad RecordsAffected con el nmero de filas afectadas por un determinado comando de actualizacin para una fila modificada de una tabla. Si se establece que el comando de actualizacin compruebe la concurrencia optimista, la propiedad RecordsAffected devolver un valor 0 cuando se haya producido una infraccin en la concurrencia optimista, ya que no se actualiz ningn registro. En tal caso se inicia una excepcin. El evento RowUpdated le permite controlar este caso y evitar la excepcin al establecer un valor RowUpdatedEventArgs.Status apropiado, como UpdateStatus.SkipCurrentRow. Para obtener ms informacin sobre el evento RowUpdated, consulte Trabajar con eventos DataAdapter. De forma opcional, es posible establecer DataAdapter.ContinueUpdateOnError como true antes de llamar a Update y responder a la informacin de error almacenada en la propiedad RowError de una fila determinada cuando Update termine. Para obtener ms informacin, vea Agregar y leer informacin de error de fila.
RowError de la fila para la que se emiti la actualizacin con el fin de reflejar la existencia de una infraccin de la concurrencia optimista. Hay que tener en cuenta que los valores de los parmetros pasados a la clusula WHERE del comando UPDATE se asignan a los valores Original de sus respectivas columnas. C# VB
// Assumes connection is a valid SqlConnection. SqlDataAdapter adapter = new SqlDataAdapter( "SELECT CustomerID, CompanyName FROM Customers ORDER BY CustomerID", connection); // The Update command checks for optimistic concurrency violations // in the WHERE clause. adapter.UpdateCommand = new SqlCommand("UPDATE Customers " + (CustomerID, CompanyName) VALUES(@CustomerID, @CompanyName) " + "WHERE CustomerID = @oldCustomerID AND CompanyName = " + @oldCompanyName", connection); adapter.UpdateCommand.Parameters.Add( "@CustomerID", SqlDbType.NChar, 5, "CustomerID"); adapter.UpdateCommand.Parameters.Add( "@CompanyName", SqlDbType.NVarChar, 30, "CompanyName"); // Pass the original values to the WHERE clause parameters. SqlParameter parameter = adapter.UpdateCommand.Parameters.Add( "@oldCustomerID", SqlDbType.NChar, 5, "CustomerID"); parameter.SourceVersion = DataRowVersion.Original; parameter = adapter.UpdateCommand.Parameters.Add( "@oldCompanyName", SqlDbType.NVarChar, 30, "CompanyName"); parameter.SourceVersion = DataRowVersion.Original; // Add the RowUpdated event handler. adapter.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated); DataSet dataSet = new DataSet(); adapter.Fill(dataSet, "Customers"); // Modify the DataSet contents. adapter.Update(dataSet, "Customers"); foreach (DataRow dataRow in dataSet.Tables["Customers"].Rows) { if (dataRow.HasErrors) Console.WriteLine(dataRow [0] + "\n" + dataRow.RowError); } protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args) { if (args.RecordsAffected == 0) { args.Row.RowError = "Optimistic Concurrency Violation Encountered"; args.Status = UpdateStatus.SkipCurrentRow;
} }