Insertar, actualizar y eliminar datos con SqlDataSource (C#)

por Scott Mitchell

Descargar PDF

En los tutoriales anteriores, vimos cómo el control ObjectDataSource permite insertar, actualizar y eliminar datos. El control SqlDataSource admite las mismas operaciones, aunque con otro enfoque, y en este tutorial se muestra cómo configurar SqlDataSource para insertar, actualizar y eliminar datos.

Introducción

Como se describe en Información general sobre la inserción, actualización y eliminación de datos, el control GridView proporciona funcionalidades integradas de actualización y eliminación, mientras que los controles DetailsView y FormView proporcionan compatibilidad con la inserción además de las funcionalidades de edición y eliminación. Estas funcionalidades de modificación de datos se pueden conectar directamente a un control de origen de datos sin necesidad de escribir una línea de código. En Información general sobre la inserción, actualización y eliminación se analizaba el uso de ObjectDataSource para facilitar la inserción, la actualización y la eliminación con los controles GridView, DetailsView y FormView. Como alternativa, se puede usar SqlDataSource en lugar de ObjectDataSource.

Recuerde que, para admitir la inserción, la actualización y la eliminación con ObjectDataSource, tenemos que especificar los métodos de capa de objeto que se invocarán para realizar las acciones de inserción, actualización o eliminación. Con SqlDataSource, es necesario proporcionar las instrucciones (o procedimientos almacenados) SQL INSERT, UPDATE y DELETE que se van a ejecutar. Como veremos en este tutorial, estas instrucciones se pueden crear manualmente o generar automáticamente mediante el Asistente para la configuración de orígenes de datos de SqlDataSource.

Nota:

Puesto que ya hemos analizado las funcionalidades de inserción, edición y eliminación de los controles GridView, DetailsView y FormView, este tutorial se centrará en la configuración del control SqlDataSource para admitir estas operaciones. Si necesita profundizar en la implementación de estas características en GridView, DetailsView y FormView, vuelva a los tutoriales de edición, inserción y eliminación de datos, empezando por Información general sobre la inserción, actualización y eliminación.

Paso 1: Especificar las instrucciones INSERT, UPDATE y DELETE

Como hemos visto en los últimos dos tutoriales, para recuperar datos de un control SqlDataSource, es necesario establecer dos propiedades:

  1. ConnectionString, que especifica a qué base de datos se va a enviar la consulta y
  2. SelectCommand, que especifica la instrucción SQL ad-hoc o el nombre del procedimiento almacenado que se va a ejecutar para devolver los resultados.

Para los valores de SelectCommand con parámetros, los valores de parámetro se especifican a través de la colección SelectParameters de SqlDataSource y pueden incluir valores codificados de forma rígida, valores de origen de parámetros comunes (campos de cadena de consulta, variables de sesión, valores de control web, etc.) o se pueden asignar mediante programación. Cuando se invoca el método Select() del control SqlDataSource, ya sea mediante programación o automáticamente desde un control web de datos, se establece una conexión a la base de datos, se asignan los valores de los parámetros a la consulta y se transfiere el comando a la base de datos. A continuación, se devuelven los resultados como DataSet o DataReader, según el valor de la propiedad DataSourceMode del control.

Además de para seleccionar datos, el control SqlDataSource se puede usar para insertar, actualizar y eliminar datos mediante las instrucciones SQL INSERT, UPDATE y DELETE prácticamente de la misma manera. Solo hay que asignar las propiedades InsertCommand, UpdateCommand y DeleteCommand y las instrucciones SWL INSERT, UPDATE y DELETE SQL que se van a ejecutar. Si las instrucciones tienen parámetros (como ocurrirá casi siempre), inclúyalos en las colecciones InsertParameters, UpdateParameters y DeleteParameters.

Una vez especificado un valor InsertCommand, UpdateCommand o DeleteCommand, estará disponible la opción Habilitar inserción, Habilitar edición o Habilitar eliminación en la etiqueta inteligente del control web de datos correspondiente. Para ilustrar esto, veamos un ejemplo de la página Querying.aspx que creamos en el tutorial Consulta de datos con el control SqlDataSource y ampliémoslo para incluir funcionalidades de eliminación.

Comience abriendo las páginas InsertUpdateDelete.aspx y Querying.aspx desde la carpeta SqlDataSource. En el Diseñador de la página Querying.aspx, seleccione SqlDataSource y GridView en el primer ejemplo (los controles ProductsDataSource y GridView1). Después de seleccionar los dos controles, vaya al menú Edición y elija Copiar (o simplemente presione Ctrl+C). A continuación, vaya al Diseñador de InsertUpdateDelete.aspx y pegue los controles. Después de mover los dos controles a InsertUpdateDelete.aspx, pruebe la página en un explorador. Debería ver los valores de las columnas ProductID, ProductName y UnitPrice de todos los registros de la tabla de base de datos Products.

All of the Products are Listed, Ordered by ProductID

Figura 1: Se enumeran todos los productos ordenados por ProductID (haga clic para ver la imagen a tamaño completo).

Adición de las propiedades DeleteCommand y DeleteParameters de SqlDataSource

En este punto, tenemos un control SqlDataSource que simplemente devuelve todos los registros de la tabla Products y un control GridView que representa estos datos. Nuestro objetivo es ampliar este ejemplo para permitir que el usuario elimine productos a través del control GridView. Para ello, es necesario especificar valores para las propiedades DeleteCommand y DeleteParameters del control SqlDataSource y, después, configurar GridView para que admita la eliminación.

Las propiedades DeleteCommand y DeleteParameters se pueden especificar de varias maneras:

  • Mediante la sintaxis declarativa.
  • Desde la ventana Propiedades del diseñador.
  • En la pantalla Especificar una instrucción SQL personalizada o un procedimiento almacenado del Asistente para la configuración de orígenes de datos.
  • Mediante el botón Avanzado de la pantalla Especificar columnas de una tabla o vista de Asistente para la configuración de orígenes de datos, que en realidad generará automáticamente la instrucción SQL DELETE y la colección de parámetros usados en las propiedades DeleteCommand y DeleteParameters.

En el paso 2 examinaremos cómo hacer que la instrucción DELETE se cree automáticamente. Por ahora, vamos a usar la ventana Propiedades del Diseñador, aunque el Asistente para la configuración de orígenes de datos o la opción de sintaxis declarativa funcionarían igual de bien.

En el Diseñador de InsertUpdateDelete.aspx, haga clic en el SqlDataSource ProductsDataSource y luego abra la ventana Propiedades (elija la ventana Propiedades en el menú Ver o simplemente presione F4). Seleccione la propiedad DeleteQuery, con lo que aparecerá un botón de puntos suspensivos.

Screenshot showing the ProductsDataSource Properties window with the DeleteQuery property selected.

Figura 2: Selección de la propiedad DeleteQuery en la ventana Propiedades.

Nota:

SqlDataSource no tiene ninguna propiedad DeleteQuery. Más bien, DeleteQuery es una combinación de las propiedades DeleteCommand y DeleteParameters y solo aparece en la ventana Propiedades cuando se visualiza la ventana a través del diseñador. Si busca la ventana Propiedades en la vista Origen, solo verá la propiedad DeleteCommand.

Haga clic en los puntos suspensivos de la propiedad DeleteQuery para abrir el cuadro de diálogo Editor de parámetros y comandos (vea la figura 3). En este cuadro de diálogo puede especificar la instrucción SQL DELETE y especificar los parámetros. Escriba la siguiente consulta en el cuadro de texto de comando DELETE (manualmente o, si lo prefiere, mediante el Generador de consultas):

DELETE FROM Products
WHERE ProductID = @ProductID

A continuación, haga clic en el botón Actualizar parámetros para agregar el parámetro @ProductID a la lista de parámetros siguientes.

Screenshot showing the Command and Parameter Editor window with the <span class=Parámetro @ProductIDagregado a la lista de parámetros del comando DELETE". />

Figura 3: Selección de la propiedad DeleteQuery en la ventana Propiedades (haga clic para ver la imagen a tamaño completo).

No proporcione ningún valor para este parámetro (deje el origen del parámetro en Ninguno). Una vez que agreguemos compatibilidad con la eliminación al control GridView, este proporcionará automáticamente el valor de este parámetro a partir del valor de la colección DataKeys para la fila cuyo botón Eliminar se haya pulsado.

Nota:

El nombre del parámetro usado en la consulta DELETEdebe ser igual que el nombre del valor DataKeyNames en GridView, DetailsView o FormView. Es decir, el parámetro de la instrucción DELETE se denomina @ProductID intencionadamente (en lugar de, por ejemplo, @ID), ya que el nombre de la columna de clave principal de la tabla Productos (y, por tanto, el valor DataKeyNames den GridView) es ProductID.

Si el nombre del parámetro y el valor DataKeyNames no coinciden, GridView no puede asignar automáticamente al parámetro el valor de la colección DataKeys.

Después de escribir la información relacionada con la eliminación en el cuadro de diálogo Editor de parámetros y comandos, haga clic en Aceptar y vaya a la vista Origen para examinar el marcado declarativo resultante:

<asp:SqlDataSource ID="ProductsDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    SelectCommand=
        "SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]"
    DeleteCommand="DELETE FROM Products WHERE ProductID = @ProductID">
    <DeleteParameters>
        <asp:Parameter Name="ProductID" />
    </DeleteParameters>
</asp:SqlDataSource>

Observe que se ha agregado la propiedad DeleteCommand, así como la sección <DeleteParameters> y el objeto de parámetro denominado productID.

Configuración de GridView para la eliminación

Con la propiedad DeleteCommand agregada, la etiqueta inteligente de GridView ahora contiene la opción Habilitar eliminación. Active esta casilla. Como se describe en Información general sobre la inserción, actualización y eliminación, esto hace que GridView agregue el campo CommandField con la propiedad ShowDeleteButton establecida en true. Como se muestra en la figura 4, cuando se visita la página a través de un explorador, se incluye el botón Eliminar. Elimine algunos productos para probar la página.

Each GridView Row Now Includes a Delete Button

Figura 4: Cada fila de GridView ahora incluye el botón Eliminar (haga clic para ver la imagen a tamaño completo).

Al hacer clic en uno de los botones Eliminar, se produce un postback, GridView asigna al parámetro ProductID el valor de la colección DataKeys para la fila cuyo botón Eliminar se haya pulsado e invoca el método Delete() de SqlDataSource. A continuación, el control SqlDataSource se conecta a la base de datos y ejecuta la instrucción DELETE. GridView se vuelve a enlazar al control SqlDataSource, con lo que se muestra el conjunto actual de productos (que ya no incluye el registro recién eliminado).

Nota:

Dado que GridView usa su colección DataKeys para rellenar los parámetros de SqlDataSource, es fundamental que la propiedad DataKeyNames de GridView esté establecida en la columna o las columnas que constituyan la clave principal y que SelectCommand de SqlDataSource devuelva esas columnas. Además, es importante que el nombre del parámetro DeleteCommand SqlDataSource esté establecido en @ProductID. Si la propiedad DataKeyNames no está establecida o el parámetro no se denomina @ProductsID, al hacer clic en el botón Eliminar se producirá un postback, pero no se eliminará realmente ningún registro.

En la figura 5 se muestra esta interacción gráficamente. Consulte de nuevo el tutorial Examinar los eventos relacionados con la inserción, actualización y eliminación para ver una explicación más detallada sobre la cadena de eventos asociados a la inserción, la actualización y la eliminación de un control web de datos.

Clicking the Delete Button in the GridView Invokes the SqlDataSource s Delete() Method

Figura 5: Al hacer clic en el botón Eliminar en GridView se invoca el método Delete() de SqlDataSource.

Paso 2: Generación automática de las instrucciones INSERT, UPDATE y DELETE.

Como se describe en el paso 1, se pueden especificar las instrucciones SQL INSERT, UPDATE y DELETE a través de la ventana Propiedades o de la sintaxis declarativa del control. Sin embargo, este enfoque requiere escribir manualmente las instrucciones SQL, lo que puede ser monótono y dar lugar a errores. Afortunadamente, el Asistente para la configuración de orígenes de datos proporciona una opción para que las instrucciones INSERT, UPDATE y DELETE se generen automáticamente en la pantalla Especificar columnas de una tabla o vista de tabla.

Vamos a explorar esta opción de generación automática. Agregue un control DetailsView al diseñador de InsertUpdateDelete.aspx y establezca la propiedad ID en ManageProducts. A continuación, en la etiqueta inteligente de DetailsView, elija Crear un nuevo origen de datos y cree un objeto SqlDataSource denominado ManageProductsDataSource.

Create a New SqlDataSource Named ManageProductsDataSource

Figura 6: Creación de un nuevo SqlDataSource denominado ManageProductsDataSource (haga clic para ver la imagen a tamaño completo).

En el Asistente para la configuración de orígenes de datos, opte por usar la cadena de conexión NORTHWINDConnectionString y haga clic en Siguiente. En la pantalla Configurar la instrucción Select, deje seleccionado el botón de radio Especificar columnas de una tabla o vista y elija la tabla Products de la lista desplegable. Seleccione las columnas ProductID, ProductName, UnitPrice y Discontinued de la lista de casillas.

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

Figura 7: Con la tabla Products, devolver las columnas ProductID, ProductName, UnitPrice y Discontinued (Haga clic para ver la imagen a tamaño completo).

Para generar automáticamente las instrucciones INSERT, UPDATE y DELETE basadas en la tabla y las columnas seleccionadas, haga clic en el botón Avanzado y active la casilla Generar instrucciones INSERT, UPDATE y DELETE.

Check the Generate INSERT, UPDATE, and DELETE statements Checkbox

Figura 8: Activación de la casilla Generar instrucciones INSERT, UPDATE y DELETE.

La casilla Generar instrucciones INSERT, UPDATE y DELETE solo se podrá activar si la tabla seleccionada tiene una clave principal y la columna o las columnas de clave principal se incluyen en la lista de columnas devueltas. La casilla Usar simultaneidad optimista, que se puede seleccionar una vez que se activa la casilla Generar instrucciones INSERT, UPDATE y DELETE, aumentará las cláusulas WHERE de las instrucciones UPDATE y DELETE resultantes para proporcionar un control de simultaneidad optimista. Por ahora, deje esta casilla desactivada; veremos la simultaneidad optimista con el control SqlDataSource en el siguiente tutorial.

Tras activar la casilla Generar instrucciones INSERT, UPDATE y DELETE, haga clic en Aceptar para volver a la pantalla Configurar instrucción Select, haga clic en Siguiente y, por último, en Finalizar, para completar el Asistente para la configuración de orígenes de datos. Tras completar el asistente, Visual Studio agregará campos BoundField a DetailsView para las columnas ProductID, ProductName y UnitPrice un campo CheckBoxField para la columna Discontinued. En la etiqueta inteligente de DetailsView, active la opción Habilitar paginación para que los usuarios visiten esta página puedan recorrer los productos. Borre también las propiedades Width y Height de DetailsView.

Tenga en cuenta que la etiqueta inteligente tiene disponibles las opciones Habilitar inserción, Habilitar edición y Habilitar eliminación. Esto se debe a que SqlDataSource contiene los valores de las propiedades InsertCommand, UpdateCommand y DeleteCommand, tal como se muestra en la sintaxis declarativa siguiente:

<asp:DetailsView ID="ManageProducts" runat="server" AllowPaging="True"
    AutoGenerateRows="False" DataKeyNames="ProductID"
    DataSourceID="ManageProductsDataSource" EnableViewState="False">
    <Fields>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
            InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
            SortExpression="UnitPrice" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
            SortExpression="Discontinued" />
    </Fields>
</asp:DetailsView>
<asp:SqlDataSource ID="ManageProductsDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    DeleteCommand=
        "DELETE FROM [Products] WHERE [ProductID] = @ProductID"
    InsertCommand=
        "INSERT INTO [Products] ([ProductName], [UnitPrice], [Discontinued])
         VALUES (@ProductName, @UnitPrice, @Discontinued)"
    SelectCommand=
        "SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued]
         FROM [Products]"
    UpdateCommand=
        "UPDATE [Products] SET [ProductName] = @ProductName,
         [UnitPrice] = @UnitPrice, [Discontinued] = @Discontinued
         WHERE [ProductID] = @ProductID">
    <DeleteParameters>
        <asp:Parameter Name="ProductID" Type="Int32" />
    </DeleteParameters>
    <UpdateParameters>
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="UnitPrice" Type="Decimal" />
        <asp:Parameter Name="Discontinued" Type="Boolean" />
        <asp:Parameter Name="ProductID" Type="Int32" />
    </UpdateParameters>
    <InsertParameters>
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="UnitPrice" Type="Decimal" />
        <asp:Parameter Name="Discontinued" Type="Boolean" />
    </InsertParameters>
</asp:SqlDataSource>

Observe cómo el control SqlDataSource tienes valores establecidos automáticamente para sus propiedades InsertCommand, UpdateCommand y DeleteCommand. El conjunto de columnas a las que se hace referencia en las propiedades InsertCommand y UpdateCommand está basado en las de la instrucción SELECT. Es decir, en lugar de tener cada columna Productos en InsertCommand y UpdateCommand, solo están las columnas especificadas en SelectCommand (excepto ProductID, que se omite porque es una columna IDENTITY, cuyo valor no se puede cambiar cuando se edita y que se asigna automáticamente al insertar). Además, para cada parámetro de las propiedades InsertCommand, UpdateCommand y DeleteCommand, hay parámetros correspondientes en las colecciones InsertParameters, UpdateParameters y DeleteParameters.

Para activar las características de modificación de datos de DetailsView, active las opciones Habilitar inserción, Habilitar edición y Habilitar eliminación en la etiqueta inteligente. Esto agrega el campo CommandField con las propiedades ShowInsertButton, ShowEditButton y ShowDeleteButton establecidas en true.

Visite la página en un explorador y observe los botones Editar, Eliminar y Nuevo incluidos en DetailsView. Al hacer clic en el botón Editar, DetailsView pasa al modo de edición, donde se muestra cada BoundField cuya propiedad ReadOnly está establecida en false (el valor predeterminado) como TextBox, y CheckBoxField como casilla.

The DetailsView s Default Editing Interface

Figura 9: Interfaz de edición predeterminada de DetailsView (haga clic para ver la imagen a tamaño completo).

Del mismo modo, puede eliminar el producto seleccionado actualmente o agregar un nuevo producto al sistema. Puesto que la instrucción InsertCommand solo funciona con las columnas ProductName, UnitPrice y Discontinued, en el momento de la inserción la base de datos asigna a las demás columnas el valor NULL o el valor predeterminado. Al igual que con ObjectDataSource, si a InsertCommand le faltan columnas de la tabla de la base de datos que no permitan valores NULL y no tengan un valor predeterminado, se producirá un error SQL al intentar ejecutar la instrucción INSERT.

Nota:

Las interfaces de inserción y edición de DetailsView carecen de cualquier tipo de personalización o validación. Para agregar controles de validación o para personalizar las interfaces, debe convertir los campos BoundField a TemplateField. Para obtener más información, consulte los tutoriales Agregar controles de validación a las interfaces de edición e inserción y Personalizar la interfaz de modificación de datos.

Tenga también en cuenta que, para actualizar y eliminar, DetailsView usa el valor DataKey del producto actual, que solo está presente si la propiedad DataKeyNames está configurada. Si la edición o eliminación parece no tener ningún efecto, asegúrese de que la propiedad DataKeyNames esté establecida.

Limitaciones de la generación automática de instrucciones SQL

Dado que la opción Generar instrucciones INSERT, UPDATE y DELETE solo está disponible al seleccionar columnas de una tabla, para las consultas más complejas tendrá que escribir sus propias instrucciones INSERT, UPDATE y DELETE, tal como hicimos en el paso 1. Normalmente, las instrucciones SQL SELECT usan expresiones JOIN para devolver datos de una o varias tablas de búsqueda con fines de visualización (como devolver el campo Categories de la tabla CategoryName al mostrar información del producto). Al mismo tiempo, es posible que deseemos permitir al usuario editar, actualizar o insertar datos en la tabla principal (Products, en este caso).

Aunque las instrucciones INSERT, UPDATE y DELETE se pueden escribir manualmente, tenga en cuenta la siguiente sugerencia para ahorrar tiempo. Inicialmente, configure SqlDataSource para que extraiga los datos de la tabla Products. Use la pantalla Especificar columnas de una tabla o vista del Asistente para la configuración de orígenes de datos para generar automáticamente las instrucciones INSERT, UPDATE y DELETE. Después de completar el asistente, elija configurar SelectQuery desde la ventana Propiedades (o vuelva al Asistente para la configuración de orígenes de datos, pero use la opción Especificar una instrucción SQL personalizada o un procedimiento almacenado). A continuación, actualice la instrucción SELECT para incluir la sintaxis JOIN. Esta técnica permite ahorrar tiempo con las instrucciones SQL generadas automáticamente y obtener una instrucción SELECT más personalizada.

Otra limitación de la generación automática de las instrucciones INSERT, UPDATE y DELETE es que las columnas de las instrucciones INSERT y UPDATE están basadas en las columnas devueltas por la instrucción SELECT. No obstante, es posible que necesitemos actualizar o insertar más o menos campos. Por ejemplo, en el ejemplo del paso 2, quizás queramos que el BoundField UnitPrice sea de solo lectura. En ese caso, no debería aparecer en UpdateCommand. O bien, es posible que deseemos establecer el valor de un campo de tabla que no aparezca en GridView. Por ejemplo, al agregar un nuevo registro, es posible que deseemos que el valor QuantityPerUnit se establezca en TODO.

Si necesita estas personalizaciones, deberá realizarlas manualmente, ya sea a través de la ventana Propiedades, la opción Especificar una instrucción SQL personalizada o un procedimiento almacenado del asistente, o la sintaxis declarativa.

Nota:

Al agregar parámetros que no tengan campos correspondientes en el control web de datos, tenga en cuenta que habrá que asignar valores a esos parámetros de alguna manera. Estos valores se podrán codificar directamente en InsertCommand o UpdateCommand, podrán proceder de algún origen predefinido (la cadena de consulta, el estado de la sesión, los controles web de la página, etc.) o se podrán asignar mediante programación, como vimos en el tutorial anterior.

Resumen

Para que los controles web de datos usen las funcionalidades integradas de inserción, edición y eliminación, el control de origen de datos al que están enlazados debe ofrecer dicha funcionalidad. Para SqlDataSource, esto significa que instrucciones SQL INSERT, UPDATE y DELETE se deben asignar a las propiedades InsertCommand, UpdateCommand y DeleteCommand. Estas propiedades y las colecciones de parámetros correspondientes se pueden agregar manualmente o generar automáticamente mediante el Asistente para la configuración de orígenes de datos. En este tutorial se examinan las dos técnicas.

Examinamos el uso de la simultaneidad optimista con ObjectDataSource en el tutorial Implementar la simultaneidad optimista. El control SqlDataSource también proporciona compatibilidad con la simultaneidad optimista. Como se indica en el paso 2, al generar automáticamente las instrucciones INSERT, UPDATE y DELETE, el asistente ofrece la opción Usar simultaneidad optimista. Como veremos en el siguiente tutorial, al usar la simultaneidad optimista con SqlDataSource se modifican las cláusulas WHERE de las instrucciones UPDATE y DELETE para asegurarse de que los valores de las demás columnas no han cambiado desde la última vez que se mostraron los datos en la página.

¡Feliz programación!

Acerca del autor

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