Como mencionamos anteriormente, los controles vinculados a datos almacenan los valores pasados a la fuente de datos en diccionarios independientes de claves, valores (nuevos valores) y valores antiguos. De forma predeterminada, SqlDataSource y ObjectDataSource ignoran el campo OldValues y solo usan claves y valores. Este comportamiento lo detecta la propiedad ConflictDetection de la fuente de datos, que está configurada en OverwriteChanges de forma predeterminada. El patrón OverwriteChanges significa "coincidir solo con el valor de la clave principal para actualizar o eliminar el registro". Esta operación significa que la actualización o eliminación de un registro no tiene en cuenta si el valor subyacente del registro ha cambiado. En circunstancias normales, el estado ideal es permitir que la operación Actualizar o Eliminar se realice correctamente solo cuando el valor de la fila de datos coincida exactamente con el valor seleccionado originalmente. En esta situación ideal, si otro usuario actualiza una fila entre el momento en que la selecciona y el momento en que la actualiza, la operación de actualización fallará. La fuente de datos también admite esta operación estableciendo la propiedad ConflictDetection en CompareAllValues. En este modo, la fuente de datos aplicará OldValues al comando o método, y utilizará estos valores para garantizar que la operación de actualización o eliminación debe coincidir con todos los valores del registro antes de actualizar o eliminar el registro. También debe establecer la propiedad OldValuesParameterFormatString en una cadena de formato de componente .NET Framework válida (como "original_{0}") para indicar cómo se debe cambiar el nombre de los parámetros en los diccionarios OldValues y Keys para distinguirlos de los parámetros NewValues.
El siguiente ejemplo de código muestra comandos SQL típicos utilizados por el control SqlDataSource en los modos OverwriteChanges y CompareAllValues. Se supone que el campo ID es el campo de clave principal. Tenga en cuenta que el último comando compara todos los valores sin procesar de las filas de datos en la cláusula WHERE, en lugar de solo las claves primarias. En este caso, OldValuesParameterFormatString de la fuente de datos debe establecerse en "original_{0}".
SELECCIONE [ID], [Nombre], [Dirección] de [Contactos]
-- Sobrescribir cambios
ACTUALIZAR [Contactos] SET [Nombre] = @Nombre, [Dirección] = @Dirección DONDE [ID] = @ID
ELIMINAR DE [Contactos] DONDE [ID] = @ID
- CompareAllValues
ACTUALIZAR [Contactos] SET [Nombre] = @Nombre, [Dirección] = @Dirección DONDE [ID] = @original_ID
Y [Nombre] = @nombre_original Y [Dirección] = @dirección_original
ELIMINAR DE [Contactos] DONDE [ID] = @original_ID Y [Nombre] = @original_Name
AND [Dirección] = @original_Address
Tenga en cuenta que OldValues no son necesarios para las operaciones de inserción y que ConflictDetection solo es significativo para las operaciones de actualización y eliminación.
El siguiente ejemplo demuestra el comportamiento cuando ocurre un conflicto. Para ejecutar este ejemplo, debe abrir dos instancias del ejemplo en dos ventanas separadas del navegador (haga clic en "Ejecutar muestra" dos veces). Luego haga clic en el botón "Editar" en la misma fila de ambos formularios para poner la fila en modo de edición. Cambie un valor en la primera ventana y haga clic en "Actualizar". Tenga en cuenta que la actualización se realizó correctamente. En la segunda ventana, ingrese un nuevo valor en la fila y haga clic en "Actualizar". Esta operación de actualización no se realizó correctamente porque el valor de la fila de datos subyacente ya se cambió en la primera operación de actualización. Este ejemplo comprueba la propiedad AffectedRows del parámetro de evento Actualizado o Eliminado, que es 0 para confirmar que se ha producido un conflicto.
<script runat="servidor">
Sub protegido SqlDataSource1_Updated (remitente como objeto, e como SqlDataSourceStatusEventArgs)
Si e.AffectedRows = 0 Entonces
Response.Write("Fila modificada, actualización cancelada<br />")
Terminar si
Fin Sub
protegido Sub SqlDataSource1_Deleted (remitente como objeto, e como SqlDataSourceStatusEventArgs)
Si e.AffectedRows = 0 Entonces
Response.Write("Fila modificada, eliminación cancelada<br />")
Terminar si
Subtítulo final
</script>
Cuando Actualizar o Eliminar utiliza la interfaz de usuario con plantilla, se conservarán los valores antiguos de los campos de enlace de datos bidireccionales que utilizan la sintaxis Bind. Para Eliminar, esto significa que debe utilizar la sintaxis Bind para los valores vinculados a datos en ItemTemplate. El propósito es conservar el valor anterior requerido para la operación de eliminación. El siguiente ejemplo demuestra esta técnica.
<Columnas>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<Plantilla de artículo>
<asp:Label ID="Label1" runat="servidor" Text='<%# Bind("ContactID") %>'></asp:Label>
</Plantilla de elemento>
<Editar plantilla de artículo>
<asp:Label ID="Label3" runat="servidor" Text='<%# Eval("ContactID") %>'></asp:Label>
</Editar plantilla de elemento>
</asp:TemplateField>
<Plantilla de artículo>
<asp:Label ID="Label2" runat="servidor" Text='<%# Bind("ContactName") %>'></asp:Label>
</Plantilla de elemento>
<Editar plantilla de artículo>
<asp:TextBox ID="TextBox1" runat="servidor" Text='<%# Bind("ContactName") %>'></asp:TextBox>
</Editar plantilla de elemento>
</asp:TemplateField>
</Columnas>
</asp:GridView>
Puede manejar los errores de detección de conflictos con suavidad indicando al usuario que los datos subyacentes han cambiado, mostrándole el valor modificado y permitiéndole elegir enviar o abandonar su operación. El siguiente ejemplo demuestra una forma posible de manejar la detección de conflictos. Tenga en cuenta que al parámetro de evento RowUpdated de DetailsView se le pasa un diccionario que se puede usar para detectar valores ingresados por el usuario. También puede configurar la propiedad KeepInEditMode de este parámetro de evento para mantener DetallesView en modo de edición mientras el usuario decide cómo manejar el conflicto. Este ejemplo prueba un enfoque similar al anterior: abre dos ventanas simultáneamente para crear actualizaciones conflictivas.
SubDetalles protegidosView1_ItemUpdated(Remitente ByVal como objeto, ByVal y como System.Web.UI.WebControls.DetailsViewUpdatedEventArgs)
Si e.AffectedRows = 0 Entonces
' Poner DetailsView en modo de edición y sincronizar con la base de datos e.KeepInEditMode = True
DetallesView1.DataBind()
' Vuelve a llenar la Vista de Detalles con valores ingresados por el usuario
Atenuar como cuadro de texto
t = DetallesView1.Filas(1).Celdas(1).Controles(0)
t.Text = e.NewValues("FechaPedido")
t = DetallesView1.Filas(2).Celdas(1).Controles(0)
t.Text = e.NewValues("País de envío")
ErrorPanel.Visible = Verdadero
Demás
ErrorPanel.Visible = Falso
Terminar si
Fin
Subprotegido SubDetallesView1_ModeChanging(ByVal remitente como objeto, ByVal y como System.Web.UI.WebControls.DetailsViewModeEventArgs)
Si e.CancelingEdit = True y también ErrorPanel.Visible = True, entonces
ErrorPanel.Visible = Falso
Terminar si
La situación es similar cuando
End Sub
usa ObjectDataSource.Tenga en cuenta que debido a que la propiedad ConflictDetection de la fuente de datos está configurada en CompareAllValues, la fuente de datos buscará una sobrecarga UpdateContact que acepte el valor sin procesar de cada campo del objeto Contact.
También puede utilizar la propiedad DataObjectTypeName y CompareAllValues juntos. En este caso, ObjectDataSource busca una sobrecarga UpdateContact que acepte solo dos parámetros (ambos de contacto). El primer parámetro es el objeto Contacto que almacena el nuevo valor y el segundo parámetro es el objeto Contacto que almacena el valor anterior.