Implementar la simultaneidad optimista con SqlDataSource (C#)

por Scott Mitchell

Descargar PDF

En este tutorial se revisan los aspectos básicos del control de simultaneidad optimista y, a continuación, se explora cómo implementarlo mediante el control SqlDataSource.

Introducción

En el tutorial anterior se ha examinado cómo agregar funcionalidades de inserción, actualización y eliminación al control SqlDataSource. En resumen, para proporcionar estas características necesitamos especificar las propiedades INSERT, UPDATEo DELETE SQL correspondientes en las propiedades de InsertCommanddel control , UpdateCommando DeleteCommand, junto con los parámetros adecuados en las colecciones InsertParameters, UpdateParametersy DeleteParameters. Aunque estas propiedades y colecciones se pueden especificar manualmente, el botón Avanzado del asistente Configurar para orígenes de datos ofrece una casilla Generar INSERT, UPDATEy DELETE instrucciones que crearán automáticamente estas instrucciones en función de la instrucción SELECT.

Junto con la casilla Generar INSERT, UPDATEy DELETE instrucciones, el cuadro de diálogo Opciones avanzadas de generación de SQL incluye una opción Usar simultaneidad optimista (vea la figura 1). Cuando se comprueba, las cláusulas WHERE de las instrucciones generadas automáticamente UPDATEy DELETE se modifican para realizar solo la actualización o eliminación si los datos de la base de datos subyacentes no se han modificado desde que el usuario cargó los datos por última vez en la cuadrícula.

You Can Add Optimistic Concurrency Support from the Advanced SQL Generation Options Dialog Box

Figura 1: Puede agregar compatibilidad con simultaneidad optimista desde el cuadro de diálogo Opciones avanzadas de generación de SQL

De nuevo en el tutorial Implementación de simultaneidad optimista examinamos los aspectos básicos del control de simultaneidad optimista y cómo agregarlo a ObjectDataSource. En este tutorial, se retocan los aspectos básicos del control de simultaneidad optimista y, a continuación, se explorará cómo implementarlo mediante SqlDataSource.

Resumen de la simultaneidad optimista

En el caso de las aplicaciones web que permiten a varios usuarios simultáneos editar o eliminar los mismos datos, existe la posibilidad de que un usuario sobrescriba accidentalmente otros cambios. En el tutorial Implementación de simultaneidad optimista he proporcionado el ejemplo siguiente:

Imagine que dos usuarios, Jisun y Sam, estaban visitando una página en una aplicación que permitía a los visitantes actualizar y eliminar productos a través de un control GridView. Ambos hacen clic en el botón Editar para Chai aproximadamente al mismo tiempo. Jisun cambia el nombre del producto a Chai Tea y hace clic en el botón Actualizar. El resultado neto es una instrucción UPDATE que se envía a la base de datos, que establece todas las de los campos actualizables del producto (aunque Jisun solo ha actualizado un campo, ProductName). En este momento, la base de datos tiene los valores Chai Tea, la categoría Bebidas, el proveedor Exótico líquidos, etc. para este producto en particular. Sin embargo, la pantalla GridView en Sam sigue apareciendo el nombre del producto en la fila GridView editable como Chai. Unos segundos después de confirmar los cambios de Jisun, Sam actualiza la categoría a Condiments y hace clic en Actualizar. Esto da como resultado una instrucción de UPDATE enviada a la base de datos que establece el nombre del producto en Chai, el CategoryID al id. de categoría de Especias correspondiente, etc. Los cambios de Jisun en el nombre del producto se han sobrescrito.

En la figura 2 se muestra esta interacción.

When Two Users Simultaneously Update a Record There s Potential for One User s Changes to Overwrite the Other s

Figura 2: cuando dos usuarios actualizan simultáneamente un registro, hay posibles cambios de un usuario para sobrescribir los otros (Hacer clic para ver la imagen de tamaño completo)

Para evitar que este escenario se desarrolle, se debe implementar una forma de control de simultaneidad. Simultaneidad optimista el foco de este tutorial funciona en la suposición de que, aunque puede haber conflictos de simultaneidad cada vez y, después, la gran mayoría del tiempo que no surgirán estos conflictos. Por lo tanto, si surge un conflicto, el control de simultaneidad optimista simplemente informa al usuario de que sus cambios no se pueden guardar porque otro usuario ha modificado los mismos datos.

Nota:

En el caso de las aplicaciones en las que se supone que habrá muchos conflictos de simultaneidad o si estos conflictos no son tolerables, se puede usar el control de simultaneidad pesimista en su lugar. Consulte el tutorial de Implementación de simultaneidad optimista para obtener una explicación más exhaustiva sobre el control de simultaneidad pesimista.

El control de simultaneidad optimista funciona asegurándose de que el registro que se actualiza o elimina tiene los mismos valores que cuando se inicia el proceso de actualización o eliminación. Por ejemplo, al hacer clic en el botón Editar de una GridView editable, los valores del registro se leen de la base de datos y se muestran en TextBoxes y otros controles Web. GridView guarda estos valores originales. Más adelante, después de que el usuario realice sus cambios y haga clic en el botón actualizar, la instrucción UPDATE usada debe tener en cuenta los valores originales más los nuevos valores y actualizar solo el registro de base de datos subyacente si los valores originales que el usuario inició la edición son idénticos a los valores que todavía están en la base de datos. En la figura 3 se muestra esta secuencia de eventos.

For the Update or Delete to Succeed, the Original Values Must Be Equal to the Current Database Values

Figura 3: para que la actualización o eliminación se realice correctamente, los valores originales deben ser iguales a los valores actuales de la base de datos (Haga clic para ver la imagen de tamaño completo)

Hay varios enfoques para implementar la simultaneidad optimista (consulte Peter A. Brombergla lógica de actualización de simultaneidad optimista para obtener un breve vistazo a una serie de opciones). La técnica usada por SqlDataSource (así como por los conjuntos de datos con tipo ADO.NET usados en nuestra capa de acceso a datos) aumenta la cláusula WHERE para incluir una comparación de todos los valores originales. La siguiente instrucción UPDATE, por ejemplo, actualiza el nombre y el precio de un producto solo si los valores de base de datos actuales son iguales a los valores que se recuperaron originalmente al actualizar el registro en GridView. Los parámetros @ProductName y @UnitPrice contienen los nuevos valores especificados por el usuario, mientras que @original_ProductName y @original_UnitPrice contienen los valores que se cargaron originalmente en GridView cuando se hizo clic en el botón Editar:

UPDATE Products SET
    ProductName = @ProductName,
    UnitPrice = @UnitPrice
WHERE
    ProductID = @original_ProductID AND
    ProductName = @original_ProductName AND
    UnitPrice = @original_UnitPrice

Como veremos en este tutorial, habilitar el control de simultaneidad optimista con SqlDataSource es tan sencillo como marcar una casilla.

Paso 1: Crear un objeto SqlDataSource que admita la simultaneidad optimista

Comience abriendo la página OptimisticConcurrency.aspx desde la carpeta SqlDataSource. Arrastre un control SqlDataSource desde el Cuadro de herramientas al Diseñador y configure suID propiedad en ProductsDataSourceWithOptimisticConcurrency. A continuación, haga clic en el vínculo Configurar origen de datos desde la etiqueta inteligente del control. En la primera pantalla del asistente, elija trabajar con el NORTHWINDConnectionString y haga clic en siguiente.

Choose to Work with the NORTHWINDConnectionString

Figura 4: Elegir trabajar con el NORTHWINDConnectionString (Haga clic para ver la imagen de tamaño completo)

En este ejemplo se agregará una clase GridView que permite a los usuarios editar la Productstabla. Por lo tanto, en la pantalla Configurar la instrucción Select, elija la tabla Products en la lista desplegable y seleccione las columnas ProductID, ProductName, UnitPricey Discontinued , como se muestra en la figura 5.

From the Products Table, Return the ProductID, ProductName, UnitPrice, and Discontinued Columns

Figura 5: en la tablaProducts, devuelve el ProductID, ProductName,UnitPricey columnas de Discontinued (Haga clic para ver la imagen de tamaño completo)

Después de seleccionar las columnas, haga clic en el botón Opciones avanzadas para abrir el cuadro de diálogo Opciones avanzadas de generación de SQL. Active las casillas Generar INSERT, UPDATEy DELETE y Usar simultaneidad optimista y haga clic en Aceptar (consulte la figura 1 para obtener una captura de pantalla). Para completar el asistente, haga clic en Siguiente y, a continuación, en finalizar.

Después de completar el Asistente para configurar orígenes de datos, dedique un momento a examinar las propiedades de DeleteCommand y UpdateCommand resultantes y las colecciones de DeleteParameters y UpdateParameters. La manera más fácil de hacerlo es hacer clic en la pestaña Origen de la esquina inferior izquierda para ver la sintaxis declarativa de la página. Allí encontrará un valor UpdateCommand de:

UPDATE [Products] SET
     [ProductName] = @ProductName,
     [UnitPrice] = @UnitPrice,
     [Discontinued] = @Discontinued
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     [UnitPrice] = @original_UnitPrice AND
     [Discontinued] = @original_Discontinued

Con siete parámetros en la colección UpdateParameters:

<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
    runat="server" ...>
    <DeleteParameters>
      ...
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="UnitPrice" Type="Decimal" />
        <asp:Parameter Name="Discontinued" Type="Boolean" />
        <asp:Parameter Name="original_ProductID" Type="Int32" />
        <asp:Parameter Name="original_ProductName" Type="String" />
        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
        <asp:Parameter Name="original_Discontinued" Type="Boolean" />
    </UpdateParameters>
    ...
</asp:SqlDataSource>

Del mismo modo,DeleteCommand la propiedad DeleteParameters y la colección deben tener un aspecto similar al siguiente:

DELETE FROM [Products]
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     [UnitPrice] = @original_UnitPrice AND
     [Discontinued] = @original_Discontinued
<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
    runat="server" ...>
    <DeleteParameters>
        <asp:Parameter Name="original_ProductID" Type="Int32" />
        <asp:Parameter Name="original_ProductName" Type="String" />
        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
        <asp:Parameter Name="original_Discontinued" Type="Boolean" />
    </DeleteParameters>
    <UpdateParameters>
        ...
    </UpdateParameters>
    ...
</asp:SqlDataSource>

Además de aumentar las WHERE cláusulas de las propiedades UpdateCommand y DeleteCommand (y agregar los parámetros adicionales a las colecciones de parámetros correspondientes), al seleccionar la opción Usar simultaneidad optimista se ajustan otras dos propiedades:

Cuando el control web de datos invoca el método Update() o Delete() SqlDataSource, pasa los valores originales. Si la propiedad ConflictDetection SqlDataSource está establecida en CompareAllValues, estos valores originales se agregan al comando. La propiedad OldValuesParameterFormatString proporciona el patrón de nomenclatura usado para estos parámetros de valor original. El Asistente para configurar orígenes de datos usa original_{0} y asigna nombres a cada parámetro original de las propiedades UpdateCommand y DeleteCommand y coleccionesUpdateParameters en DeleteParameters consecuencia.

Nota:

Puesto que no usamos las funcionalidades de inserción del control SqlDataSource, no dude en quitar la propiedad InsertCommand y su colección InsertParameters.

Control correcto de los valores deNULL

Desafortunadamente, las instrucciones aumentadas UPDATE y DELETE generadas automáticamente por el Asistente para configurar orígenes de datos al usar la simultaneidad optimista no trabajar con registros que contienen valores NULL. Para ver por qué, considere nuestras instancias de SqlDataSource s UpdateCommand:

UPDATE [Products] SET
     [ProductName] = @ProductName,
     [UnitPrice] = @UnitPrice,
     [Discontinued] = @Discontinued
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     [UnitPrice] = @original_UnitPrice AND
     [Discontinued] = @original_Discontinued

La columna UnitPrice de la tabla Products puede tener valores NULL. Si un registro determinado tiene un NULL valor para UnitPrice, la parte WHERE de la cláusula [UnitPrice] = @original_UnitPrice siempre se evaluará como False porque NULL = NULL siempre devuelve False. Por lo tanto, los registros que contienen valores de NULL no se pueden editar ni eliminar, ya que las instrucciones UPDATE y DELETEWHERE cláusulas no devolverán ninguna fila para actualizar ni eliminar.

Nota:

Este error se informó por primera vez a Microsoft en junio de 2004 en SqlDataSource genera instrucciones SQL incorrectas y, según se informa, está programado para corregirse en la próxima versión de ASP.NET.

Para corregirlo, tenemos que actualizar manualmente las cláusulas WHERE en las propiedades UpdateCommand y DeleteCommand para todas las columnas de que pueden tener valores NULL. En general, cambie [ColumnName] = @original_ColumnName a:

(
   ([ColumnName] IS NULL AND @original_ColumnName IS NULL)
     OR
   ([ColumnName] = @original_ColumnName)
)

Esta modificación se puede realizar directamente a través del marcado declarativo, a través de las opciones UpdateQuery o DeleteQuery de la ventana Propiedades, o a través de las pestañas UPDATE y DELETE de la opción Especificar una instrucción SQL personalizada o un procedimiento almacenado en el Asistente para configurar orígenes de datos. De nuevo, esta modificación debe realizarse para cada columna de la UpdateCommand cláusula y DeleteCommand s WHERE que puede contener NULL valores.

Aplicar esto a nuestro ejemplo da como resultado los siguientes valores modificados UpdateCommand y DeleteCommand :

UPDATE [Products] SET
     [ProductName] = @ProductName,
     [UnitPrice] = @UnitPrice,
     [Discontinued] = @Discontinued
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
        OR ([UnitPrice] = @original_UnitPrice)) AND
     [Discontinued] = @original_Discontinued
DELETE FROM [Products]
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
        OR ([UnitPrice] = @original_UnitPrice)) AND
     [Discontinued] = @original_Discontinued

Paso 2: Agregar un control GridView con opciones de edición y eliminación

Con SqlDataSource configurado para admitir la simultaneidad optimista, todo lo que queda es agregar un control web de datos a la página que utiliza este control de simultaneidad. En este tutorial, vamos a agregar una clase GridView que proporciona funciones de edición y eliminación. Para ello, arrastre GridView desde el cuadro de herramientas al diseñador y establezca su en IDProducts. Desde la etiqueta inteligente gridView, vincule al control SqlDataSource agregado en el ProductsDataSourceWithOptimisticConcurrency paso 1. Por último, active las opciones Habilitar edición y Habilitar eliminación de la etiqueta inteligente.

Bind the GridView to the SqlDataSource and Enable Editing and Deleting

Figura 6: Enlazar GridView a SqlDataSource y habilitar edición y eliminación (haga clic para ver la imagende tamaño completo)

Después de agregar GridView, configure su apariencia quitando BoundField ProductID, cambiando la ProductName propiedad BoundField s HeaderText a Product y actualizando BoundField UnitPrice para que su HeaderText propiedad sea simplemente Price. Idealmente, mejoraríamos la interfaz de edición para incluir un RequiredFieldValidator para el ProductName valor y un CompareValidator para el UnitPrice valor (para asegurarse de que es un valor numérico con formato correcto). Consulte el tutorial Personalización de la interfaz de modificación de datos para obtener un vistazo más detallado a la personalización de la interfaz de edición de GridView.

Nota:

El estado de vista de GridView debe estar habilitado, ya que los valores originales pasados de GridView a SqlDataSource se almacenan en estado de vista.

Después de realizar estas modificaciones en GridView, el marcado declarativo GridView y SqlDataSource deben ser similares a los siguientes:

<asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
    runat="server" ConflictDetection="CompareAllValues"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    DeleteCommand=
        "DELETE FROM [Products]
         WHERE [ProductID] = @original_ProductID
         AND [ProductName] = @original_ProductName
         AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
              OR ([UnitPrice] = @original_UnitPrice))
         AND [Discontinued] = @original_Discontinued"
    OldValuesParameterFormatString=
        "original_{0}"
    SelectCommand=
        "SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued]
         FROM [Products]"
    UpdateCommand=
        "UPDATE [Products]
         SET [ProductName] = @ProductName, [UnitPrice] = @UnitPrice,
            [Discontinued] = @Discontinued
         WHERE [ProductID] = @original_ProductID
         AND [ProductName] = @original_ProductName
         AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
            OR ([UnitPrice] = @original_UnitPrice))
        AND [Discontinued] = @original_Discontinued">
    <DeleteParameters>
        <asp:Parameter Name="original_ProductID" Type="Int32" />
        <asp:Parameter Name="original_ProductName" Type="String" />
        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
        <asp:Parameter Name="original_Discontinued" Type="Boolean" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="UnitPrice" Type="Decimal" />
        <asp:Parameter Name="Discontinued" Type="Boolean" />
        <asp:Parameter Name="original_ProductID" Type="Int32" />
        <asp:Parameter Name="original_ProductName" Type="String" />
        <asp:Parameter Name="original_UnitPrice" Type="Decimal" />
        <asp:Parameter Name="original_Discontinued" Type="Boolean" />
    </UpdateParameters>
</asp:SqlDataSource>
<asp:GridView ID="Products" runat="server"
    AutoGenerateColumns="False" DataKeyNames="ProductID"
    DataSourceID="ProductsDataSourceWithOptimisticConcurrency">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price"
            SortExpression="UnitPrice" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Columns>
</asp:GridView>

Para ver el control de simultaneidad optimista en acción, abra dos ventanas del explorador y cargue la OptimisticConcurrency.aspx página en ambos. Haga clic en los botones Editar del primer producto en ambos exploradores. En un explorador, cambie el nombre del producto y haga clic en Actualizar. El explorador devolverá postback y GridView volverá a su modo de edición previa, mostrando el nuevo nombre del producto para el registro recién editado.

En la segunda ventana del explorador, cambie el precio (pero deje el nombre del producto como su valor original) y haga clic en Actualizar. En postback, la cuadrícula vuelve a su modo de edición previa, pero el cambio al precio no se registra. El segundo explorador muestra el mismo valor que el primero con el nuevo nombre del producto con el precio anterior. Los cambios realizados en la segunda ventana del explorador se perdieron. Además, los cambios se perdieron bastante silenciosamente, ya que no había ninguna excepción o mensaje que indica que se acaba de producir una infracción de simultaneidad.

The Changes in the Second Browser Window Were Silently Lost

Figura 7: Los cambios en la segunda ventana del explorador se perdieron silenciosamente (haga clic para ver la imagende tamaño completo)

La razón por la que no se confirmaban los cambios del segundo explorador era porque la cláusula WHERE de la instrucción UPDATE filtraba todos los registros y, por tanto, no afectaba a ninguna fila. Echemos un vistazo a la instrucción UPDATE de nuevo:

UPDATE [Products] SET
     [ProductName] = @ProductName,
     [UnitPrice] = @UnitPrice,
     [Discontinued] = @Discontinued
WHERE
     [ProductID] = @original_ProductID AND
     [ProductName] = @original_ProductName AND
     (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR
        ([UnitPrice] = @original_UnitPrice)) AND
     [Discontinued] = @original_Discontinued

Cuando la segunda ventana del explorador actualiza el registro, el nombre del producto original especificado en la WHERE cláusula no coincide con el nombre de producto existente (ya que el primer explorador cambió). Por lo tanto, la instrucción [ProductName] = @original_ProductName devuelve False y UPDATE no afecta a ningún registro.

Nota:

La eliminación funciona de la misma manera. Con dos ventanas del explorador abiertas, empiece editando un producto determinado con uno y, a continuación, guardando sus cambios. Después de guardar los cambios en un explorador, haga clic en el botón Eliminar del mismo producto en el otro. Dado que los valores originales no coinciden en la cláusula de la DELETE instrucción s WHERE, se produce un error en la eliminación silenciosa.

Desde la perspectiva del usuario final en la segunda ventana del explorador, después de hacer clic en el botón Actualizar, la cuadrícula vuelve al modo de edición previa, pero se perdieron sus cambios. Sin embargo, no hay comentarios visuales que sus cambios no se han pegado. Idealmente, si los cambios de un usuario se pierden en una infracción de simultaneidad, se les notificaría y, quizás, mantener la cuadrícula en modo de edición. Veamos cómo hacerlo.

Paso 3: Determinar cuándo se ha producido una infracción de simultaneidad

Dado que una infracción de simultaneidad rechaza los cambios realizados, sería agradable avisar al usuario cuando se ha producido una infracción de simultaneidad. Para alertar al usuario, vamos a agregar un control Web de etiqueta a la parte superior de la página denominada ConcurrencyViolationMessage cuya Text propiedad muestra el siguiente mensaje: Ha intentado actualizar o eliminar un registro que otro usuario actualizó simultáneamente. Revise los cambios del otro usuario y vuelva a rehacer la actualización o eliminación. Establezca la propiedad del control Label en CssClass Warning, que es una clase CSS definida en Styles.css que muestra texto en rojo, cursiva, negrita y fuente grande. Por último, establezca las propiedades Label s Visible y EnableViewState en false. Esto ocultará la etiqueta, excepto para aquellos postbacks en los que se establezca explícitamente su Visible propiedad trueen.

Add a Label Control to the Page to Display the Warning

Figura 8: Agregar un control de etiqueta a la página para mostrar la advertencia (Haga clic para ver la imagen de tamaño completo)

Al realizar una actualización o eliminación, los controladores de eventos de GridView RowUpdated y RowDeleted se activan después de que su control de origen de datos haya realizado la actualización o eliminación solicitadas. Podemos determinar cuántas filas se vieron afectadas por la operación de estos controladores de eventos. Si se han afectado cero filas, queremos mostrar la ConcurrencyViolationMessage etiqueta.

Cree un controlador de eventos para los RowUpdated eventos y RowDeleted agregue el código siguiente:

protected void Products_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
    if (e.AffectedRows == 0)
    {
        ConcurrencyViolationMessage.Visible = true;
        e.KeepInEditMode = true;
        // Rebind the data to the GridView to show the latest changes
        Products.DataBind();
    }
}
protected void Products_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
    if (e.AffectedRows == 0)
        ConcurrencyViolationMessage.Visible = true;
}

En ambos controladores de eventos comprobamos la propiedad e.AffectedRows y, si es igual a 0, establezca la propiedad Visible Etiqueta de ConcurrencyViolationMessage en true. En el controlador de eventos RowUpdated, también indicamos a GridView que permanezca en modo de edición estableciendo la propiedad KeepInEditMode en true. Al hacerlo, es necesario volver a enlazar los datos a la cuadrícula para que los demás datos del usuario se carguen en la interfaz de edición. Esto se logra llamando al método DataBind() GridView.

Como se muestra en la figura 9, con estos dos controladores de eventos, se muestra un mensaje muy notable cada vez que se produce una infracción de simultaneidad.

A Message is Displayed in the Face of a Concurrency Violation

Figura 9: se muestra un mensaje en la cara de una infracción de simultaneidad (Haga clic para ver la imagen de tamaño completo)

Resumen

Al crear una aplicación web donde varios usuarios simultáneos pueden editar los mismos datos, es importante tener en cuenta las opciones de control de simultaneidad. De forma predeterminada, los controles web de datos ASP.NET y los controles de origen de datos no emplean ningún control de simultaneidad. Como vimos en este tutorial, la implementación del control de simultaneidad optimista con SqlDataSource es relativamente rápida y fácil. SqlDataSource controla la mayor parte del trabajo para agregar cláusulas de WHERE aumentadas a las instrucciones UPDATE y DELETE generadas automáticamente, pero hay algunas sutilezas en el control de columnas de valorNULL, como se describe en la sección Control correcto de valores NULL.

Este tutorial concluye nuestro examen de SqlDataSource. Nuestros tutoriales restantes volverán a trabajar con datos mediante ObjectDataSource y la arquitectura en capas.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Puede ponerse en contacto con él en mitchell@4GuysFromRolla.com. o a través de su blog, que se puede encontrar en http://ScottOnWriting.NET.