Compartir a través de


Actualización por lotes (C#)

de Scott Mitchell

Descargar PDF

Aprenda a actualizar varios registros de base de datos en una sola operación. En la capa de interfaz de usuario, creamos una clase GridView donde se puede editar cada fila. En la capa de acceso a datos encapsulamos las varias operaciones de actualización dentro de una transacción para asegurarse de que todas las actualizaciones se realicen correctamente o de que todas las actualizaciones se revierten.

Introducción

En el tutorial anterior vimos cómo ampliar la capa de acceso a datos para agregar compatibilidad con las transacciones de base de datos. Las transacciones de base de datos garantizan que una serie de instrucciones de modificación de datos se tratarán como una operación atómica, lo que garantiza que todas las modificaciones producirán errores o que todas se realizarán correctamente. Con esta funcionalidad DAL de bajo nivel fuera del camino, estamos listos para dedicar nuestra atención a la creación de interfaces de modificación de datos por lotes.

En este tutorial se creará una clase GridView donde se puede editar cada fila (vea la figura 1). Puesto que cada fila se representa en su interfaz de edición, no es necesario una columna de botones Editar, Actualizar y Cancelar. En su lugar, hay dos botones Actualizar productos en la página que, cuando se hace clic, enumeran las filas de GridView y actualizan la base de datos.

Cada fila de GridView es Editable

Figura 1: Cada fila de GridView es Editable (Haga clic para ver la imagen de tamaño completo)

¡Comencemos!

Nota:

En el tutorial Realización de actualizaciones por lotes hemos creado una interfaz de edición por lotes mediante el control DataList. Este tutorial difiere del anterior en que se usa gridView y la actualización por lotes se realiza dentro del ámbito de una transacción. Después de completar este tutorial, le recomendamos que vuelva al tutorial anterior y actualícelo para usar la funcionalidad relacionada con transacciones de base de datos agregada en el tutorial anterior.

Examinar los pasos para hacer que todas las filas gridView sean editables

Como se describe en el tutorial Introducción a la inserción, actualización y eliminación de datos , GridView ofrece compatibilidad integrada para editar sus datos subyacentes por fila. Internamente, GridView indica qué fila se puede editar a través de su EditIndex propiedad. A medida que GridView se enlaza a su origen de datos, comprueba cada fila para ver si el índice de la fila es igual al valor de EditIndex. Si es así, los campos de la fila se muestran mediante sus interfaces de edición. Para BoundFields, la interfaz de edición es un TextBox cuya Text propiedad se asigna al valor del campo de datos especificado por la propiedad BoundField s DataField . Para TemplateFields, EditItemTemplate se usa en lugar de ItemTemplate.

Recuerde que el flujo de trabajo de edición se inicia cuando un usuario hace clic en un botón Editar de fila. Esto provoca una devolución de datos, establece la propiedad GridView s EditIndex en el índice de la fila en la que se hace clic y vuelve a enlazar los datos a la cuadrícula. Cuando se hace clic en el botón Cancelar de una fila, en la devolución de datos, EditIndex se establece en un valor de -1 antes de volver a enlazar los datos a la cuadrícula. Dado que las filas de GridView comienzan a indexar en cero, la configuración EditIndex de -1 tiene el efecto de mostrar GridView en modo de solo lectura.

La EditIndex propiedad funciona bien para la edición por fila, pero no está diseñada para la edición por lotes. Para que todo GridView sea editable, es necesario que cada fila se represente mediante su interfaz de edición. La manera más fácil de lograrlo es crear donde cada campo editable se implementa como templateField con su interfaz de edición definida en .ItemTemplate

En los pasos siguientes, crearemos una gridView completamente editable. En el paso 1, empezaremos creando GridView y objectDataSource y convirtiendo sus BoundFields y CheckBoxField en TemplateFields. En los pasos 2 y 3 moveremos las interfaces de edición de TemplateFields EditItemTemplate a sus ItemTemplate s.

Paso 1: Mostrar información del producto

Antes de preocuparnos por la creación de una clase GridView en la que se pueden editar las filas, comencemos simplemente mostrando la información del producto. Abra la BatchUpdate.aspx página en la BatchData carpeta y arrastre GridView desde el Cuadro de Herramientas al Diseñador. Establezca el GridView en ID, ProductsGrid y, desde su etiqueta inteligente, elija enlazarlo a un nuevo ObjectDataSource denominado ProductsDataSource. Configure ObjectDataSource para recuperar sus datos del método de la ProductsBLL clase s GetProducts .

Configurar ObjectDataSource para usar la clase ProductsBLL

Figura 2: Configurar objectDataSource para usar la clase (ProductsBLL imagen de tamaño completo)

Recuperar los datos del producto mediante el método GetProducts

Figura 3: Recuperar los datos del producto mediante el método (GetProducts la imagen de tamaño completo)

Al igual que GridView, las características de modificación de ObjectDataSource están diseñadas para funcionar por fila. Para actualizar un conjunto de registros, es necesario escribir un poco de código en la clase de código subyacente de la página ASP.NET que agrupa por lotes los datos y los pasa al BLL. Por lo tanto, establezca las listas desplegables en las pestañas UPDATE, INSERT y DELETE de ObjectDataSource en (Ninguno). Haga clic en Finalizar para completar el asistente.

Establezca las listas de Drop-Down en las pestañas UPDATE, INSERT y DELETE en (Ninguno)

Figura 4: Establecer las listas de Drop-Down en las pestañas UPDATE, INSERT y DELETE en (Ninguno) (Haga clic para ver la imagen de tamaño completo)

Después de completar el Asistente para configurar orígenes de datos, el marcado declarativo de ObjectDataSource debe ser similar al siguiente:

<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>

Al completar el asistente para configurar orígenes de datos, Visual Studio crea BoundFields y un CheckBoxField para los campos de datos del producto dentro del GridView. En este tutorial, permitiremos que el usuario vea y edite el nombre del producto, la categoría, el precio y el estado descontinuado. Elimina todo excepto los campos ProductName, CategoryName, UnitPrice y Discontinued y renombra las propiedades de los tres primeros campos a Producto, Categoría y Precio, respectivamente. Por último, active las casillas Habilitar paginación y Habilitación de la ordenación en la etiqueta inteligente de GridView.

En este punto, GridView tiene tres BoundFields (ProductName, CategoryNamey ) y UnitPriceun CheckBoxField (Discontinued). Es necesario convertir estos cuatro campos en TemplateFields y, a continuación, mover la interfaz de edición de TemplateField s EditItemTemplate a su ItemTemplate.

Nota:

Hemos explorado la creación y personalización de TemplateFields en el tutorial Personalización de la interfaz de modificación de datos . Te guiaremos por los pasos para convertir BoundFields y CheckBoxField en TemplateFields y definir sus interfaces de edición en sus ItemTemplate s, pero si te quedas bloqueado o necesitas un recordatorio, no dudes en consultar este tutorial anterior.

En la etiqueta inteligente de GridView, haga clic en el vínculo Editar columnas para abrir el cuadro de diálogo Campos. A continuación, seleccione cada campo y haga clic en el vínculo Convertir este campo en un vínculo TemplateField.

Convertir los BoundFields y CheckBoxField existentes en TemplateField

Figura 5: Convertir los boundFields y CheckBoxField existentes en TemplateField

Ahora que cada campo es templateField, estamos listos para mover la interfaz de edición de los EditItemTemplate s a los ItemTemplate s.

Paso 2: Crear las interfacesProductName, UnitPrice, y DiscontinuedEditar

La creación de las ProductNameinterfaces de edición , UnitPricey Discontinued son el tema de este paso y son bastante sencillas, ya que cada interfaz ya está definida en templateField s EditItemTemplate. La creación de la CategoryName interfaz de edición es un poco más implicada, ya que es necesario crear un DropDownList de las categorías aplicables. Esta CategoryName interfaz de edición se aborda en el paso 3.

Comencemos con TemplateField ProductName . Haga clic en el vínculo Editar plantillas de la etiqueta inteligente gridView y explore en profundidad a ProductName TemplateField s EditItemTemplate. Seleccione el Cuadro de texto, cópielo en el Portapapeles y péguelo en templateField ProductName s ItemTemplate. Cambie la propiedad ID del TextBox a ProductName.

A continuación, agregue RequiredFieldValidator a ItemTemplate para asegurarse de que el usuario proporciona un valor para cada nombre de producto. Establezca la ControlToValidate propiedad en ProductName, la ErrorMessage propiedad en Debe proporcionar el nombre del producto. y establecer la propiedad Text en *. Después de realizar estas adiciones a ItemTemplate, la pantalla debe tener un aspecto similar a la figura 6.

ProductName TemplateField ahora incluye un textBox y un RequiredFieldValidator

Figura 6: TemplateField ProductName ahora incluye un TextBox y un RequiredFieldValidator (Haga clic para ver la imagen a tamaño completo)

Para la UnitPrice interfaz de edición, empiece por copiar el TextBox de EditItemTemplate a ItemTemplate. A continuación, coloque el símbolo $ delante del TextBox y establezca la propiedad de ID en UnitPrice y la propiedad de Columns en 8.

Agregue también compareValidator a s UnitPriceItemTemplate para asegurarse de que el valor especificado por el usuario sea un valor de moneda válido mayor o igual que 0,00 USD. Establezca la propiedad del validador a ControlToValidate UnitPrice, su propiedad a ErrorMessage Debe especificar un valor de moneda válido. Omita cualquier símbolo de moneda., su Text propiedad en *, su Type propiedad en Currency, su Operator propiedad en GreaterThanEqualy su ValueToCompare propiedad en 0 .

Agregue un CompareValidator para asegurarse de que el precio especificado es un valor de moneda no negativo

Figura 7: Agregar un compareValidator para asegurarse de que el precio especificado es un valor de moneda no negativo (haga clic para ver la imagen de tamaño completo)

Para el campo de plantilla Discontinued, puede utilizar la casilla de verificación ya definida en ItemTemplate. Simplemente establezca su ID en Descontinuado y la propiedad Enabled en true.

Paso 3: Crear la interfaz deCategoryNameedición

La interfaz de edición de TemplateField CategoryName s EditItemTemplate contiene un TextBox que muestra el valor del CategoryName campo de datos. Es necesario reemplazarlo por un DropDownList que muestre las posibles categorías.

Nota:

El tutorial Personalización de la interfaz de modificación de datos contiene una explicación más exhaustiva y completa sobre la personalización de una plantilla para incluir un DropDownList en lugar de un TextBox. Aunque los pasos aquí están completos, se presentan de forma concisa. Para obtener un vistazo más detallado a la creación y configuración de las categorías DropDownList, consulte el tutorial Personalización de la interfaz de modificación de datos .

Arrastre un DropDownList desde el Cuadro de herramientas hasta el TemplateField CategoryNameItemTemplate, estableciendo su ID a Categories. En este punto, normalmente definiríamos el origen de datos de DropDownLists a través de su etiqueta inteligente, creando un nuevo ObjectDataSource. Sin embargo, esto agregará objectDataSource dentro de ItemTemplate, lo que dará como resultado una instancia objectDataSource creada para cada fila gridView. En su lugar, vamos a crear objectDataSource fuera de TemplateFields de GridView. Finalice la edición de la plantilla y arrastre un ObjectDataSource desde el Cuadro de herramientas al Diseñador, debajo del ProductsDataSource ObjectDataSource. Asigne al nuevo nombre ObjectDataSource CategoriesDataSource y configúrelo para usar el método de la CategoriesBLL clase s GetCategories .

Configurar ObjectDataSource para usar la clase CategoriesBLL

Figura 8: Configurar objectDataSource para usar la clase (CategoriesBLL imagen de tamaño completo)

Recuperar los datos de categoría mediante el método GetCategories

Figura 9: Recuperar los datos de categoría mediante el método (GetCategories la imagen de tamaño completo)

Puesto que este ObjectDataSource se usa simplemente para recuperar datos, establezca las listas desplegables en las pestañas UPDATE y DELETE en (Ninguno). Haga clic en Finalizar para completar el asistente.

Establezca las listas de Drop-Down en las pestañas UPDATE y DELETE en (Ninguno)

Figura 10: Establecer las listas de Drop-Down en las pestañas UPDATE y DELETE en (Ninguno) (Haga clic para ver la imagen de tamaño completo)

Después de completar el asistente, la marca de declaración del CategoriesDataSource debería verse de la siguiente manera:

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Con el CategoriesDataSource creado y configurado, vuelva a TemplateField CategoryName s ItemTemplate y, desde la etiqueta inteligente DropDownList, haga clic en el vínculo Elegir origen de datos. En el Asistente para configuración del origen de datos, seleccione la CategoriesDataSource opción de la primera lista desplegable y elija usar CategoryName para la presentación y CategoryID como valor.

Enlace dropDownList a CategoriesDataSource

Figura 11: Enlazar dropDownList a CategoriesDataSource (haga clic para ver la imagen de tamaño completo)

En este momento, DropDownList Categories enumera todas las categorías, pero aún no selecciona automáticamente la categoría adecuada para el producto enlazado a la fila GridView. Para lograr esto, necesitamos establecer las Categories DropDownLists SelectedValue al valor del CategoryID producto. Haga clic en el vínculo "Editar DataBindings" de la etiqueta inteligente del DropDownList y asocie la propiedad SelectedValue con el CategoryID campo de datos, como se muestra en la figura 12.

Enlace el valor CategoryID del producto a la propiedad SelectedValue de DropDownList

Figura 12: Enlazar el valor del CategoryID producto a la propiedad DropDownList s SelectedValue

Queda un último problema: si el producto no tiene especificado un valor CategoryID, la instrucción de enlace de datos en SelectedValue producirá una excepción. Esto se debe a que DropDownList contiene solo elementos para las categorías y no ofrece una opción para los productos que tienen un NULL valor de base de datos para CategoryID. Para solucionar esto, establezca la propiedad de la DropDownList en AppendDataBoundItems y agregue un nuevo elemento a la DropDownList, omitiendo la propiedad true de la sintaxis declarativa. Es decir, asegúrese de que la Categories sintaxis declarativa de DropDownList es similar a la siguiente:

<asp:DropDownList ID="Categories" runat="server" AppendDataBoundItems="True" 
    DataSourceID="CategoriesDataSource" DataTextField="CategoryName" 
    DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'>
    <asp:ListItem Value=">-- Select One --</asp:ListItem>
</asp:DropDownList>

Tenga en cuenta cómo <asp:ListItem Value=""> -- Select One (Seleccionar uno) tiene su Value atributo establecido explícitamente en una cadena vacía. Consulte el tutorial Personalización de la interfaz de modificación de datos para obtener una explicación más detallada sobre por qué se necesita este elemento DropDownList adicional para controlar el NULL caso y por qué la asignación de la Value propiedad a una cadena vacía es esencial.

Nota:

Hay un posible problema de rendimiento y escalabilidad que vale la pena mencionar. Puesto que cada fila tiene un DropDownList que usa CategoriesDataSource como origen de datos, el método de la CategoriesBLL clase s GetCategories se denominará n veces por visita de página, donde n es el número de filas de GridView. Estas n llamadas resultan en GetCategories consultas a la base de datos. Este impacto en la base de datos podría reducirse almacenando en caché las categorías devueltas en una caché por solicitud o a través de la capa de almacenamiento en caché mediante una dependencia de almacenamiento en caché de SQL o una expiración muy corta basada en el tiempo.

Paso 4: Completar la interfaz de edición

Hemos realizado una serie de cambios en las plantillas de GridView sin pausar para ver el progreso. Dedique un momento a ver nuestro progreso a través de un explorador. Como se muestra en la figura 13, cada fila se representa mediante su ItemTemplate, que contiene la interfaz de edición de la celda.

Cada fila de la vista de cuadrícula es editable

Figura 13: Cada fila GridView es Editable (Haga clic para ver la imagen de tamaño completo)

Hay algunos problemas de formato menores que debemos tener en cuenta en este momento. En primer lugar, tenga en cuenta que el UnitPrice valor contiene cuatro puntos decimales. Para corregirlo, vuelva a los UnitPrice TemplateFields ItemTemplate y, desde la etiqueta inteligente de TextBox, haga clic en el vínculo Editar DataBindings. A continuación, especifique que la Text propiedad debe tener el formato de un número.

Dar formato a la propiedad Text como un número

Figura 14: Dar formato a la Text propiedad como un número

En segundo lugar, centremos la casilla en la Discontinued columna (en lugar de tenerla alineada a la izquierda). Haga clic en Editar columnas desde la etiqueta inteligente GridView y seleccione TemplateField Discontinued en la lista de campos de la esquina inferior izquierda. Profundice en ItemStyle y establezca la propiedad HorizontalAlign en Centro como se muestra en la figura 15.

Centrar la casilla descontinuada

Figura 15: Centrar la Discontinued casilla de verificación

A continuación, agregue un control ValidationSummary a la página y establezca su propiedad ShowMessageBox en true y su propiedad ShowSummary en false. Agregue también los controles Web de botón que, cuando se hagan clic, actualizarán los cambios del usuario. En concreto, agregue dos controles Web Button, uno encima de GridView y otro debajo de él, configurando las propiedades de ambos controles Text en "Update Products".

Dado que la interfaz de edición de GridView se define en sus TemplateFields ItemTemplate s, los EditItemTemplate s son superfluos y se pueden eliminar.

Una vez que hagas los cambios de formato mencionados anteriormente, agregues los controles Button y quites los EditItemTemplate innecesarios, la sintaxis declarativa de la página debe ser similar a la siguiente:

<p>
    <asp:Button ID="UpdateAllProducts1" runat="server" Text="Update Products" />
</p>
<p>
    <asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False" 
        DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
        AllowPaging="True" AllowSorting="True">
        <Columns>
            <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
                <ItemTemplate>
                    <asp:TextBox ID="ProductName" runat="server" 
                        Text='<%# Bind("ProductName") %>'></asp:TextBox>
                    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
                        ControlToValidate="ProductName"
                        ErrorMessage="You must provide the product's name." 
                        runat="server">*</asp:RequiredFieldValidator>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Category" 
                SortExpression="CategoryName">
                <ItemTemplate>
                    <asp:DropDownList ID="Categories" runat="server" 
                        AppendDataBoundItems="True" 
                        DataSourceID="CategoriesDataSource"
                        DataTextField="CategoryName" 
                        DataValueField="CategoryID" 
                        SelectedValue='<%# Bind("CategoryID") %>'>
                        <asp:ListItem>-- Select One --</asp:ListItem>
                    </asp:DropDownList>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Price" 
                SortExpression="UnitPrice">
                <ItemTemplate>
                    $<asp:TextBox ID="UnitPrice" runat="server" Columns="8" 
                        Text='<%# Bind("UnitPrice", "{0:N}") %>'></asp:TextBox>
                    <asp:CompareValidator ID="CompareValidator1" runat="server" 
                        ControlToValidate="UnitPrice"
                        ErrorMessage="You must enter a valid currency value. 
                                      Please omit any currency symbols."
                        Operator="GreaterThanEqual" Type="Currency" 
                        ValueToCompare="0">*</asp:CompareValidator>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
                <ItemTemplate>
                    <asp:CheckBox ID="Discontinued" runat="server" 
                        Checked='<%# Bind("Discontinued") %>' />
                </ItemTemplate>
                <ItemStyle HorizontalAlign="Center" />
            </asp:TemplateField>
        </Columns>
    </asp:GridView>
</p>
<p>
    <asp:Button ID="UpdateAllProducts2" runat="server" Text="Update Products" />
    <asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}"
        SelectMethod="GetProducts" TypeName="ProductsBLL">
    </asp:ObjectDataSource>
    <asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
        OldValuesParameterFormatString="original_{0}"
        SelectMethod="GetCategories" TypeName="CategoriesBLL">
    </asp:ObjectDataSource>
    <asp:ValidationSummary ID="ValidationSummary1" runat="server" 
        ShowMessageBox="True" ShowSummary="False" />
</p>

En la figura 16 se muestra esta página cuando se ve a través de un explorador después de agregar los controles Web de botón y los cambios de formato realizados.

La página ahora incluye dos botones actualizar productos

Figura 16: La página ahora incluye dos botones actualizar productos (haga clic para ver la imagen de tamaño completo)

Paso 5: Actualización de los productos

Cuando un usuario visita esta página, realizará sus modificaciones y, a continuación, haga clic en uno de los dos botones Actualizar productos. En ese momento es necesario guardar de alguna manera los valores especificados por el usuario para cada fila en una ProductsDataTable instancia y, a continuación, pasarlo a un método BLL que luego pasará esa ProductsDataTable instancia al método dal.UpdateWithTransaction El UpdateWithTransaction método , que creamos en el tutorial anterior, garantiza que el lote de cambios se actualizará como una operación atómica.

Cree un método denominado BatchUpdate en BatchUpdate.aspx.cs y agregue el código siguiente:

private void BatchUpdate()
{
    // Enumerate the GridView's Rows collection and create a ProductRow
    ProductsBLL productsAPI = new ProductsBLL();
    Northwind.ProductsDataTable products = productsAPI.GetProducts();
    foreach (GridViewRow gvRow in ProductsGrid.Rows)
    {
        // Find the ProductsRow instance in products that maps to gvRow
        int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
        Northwind.ProductsRow product = products.FindByProductID(productID);
        if (product != null)
        {
            // Programmatically access the form field elements in the 
            // current GridViewRow
            TextBox productName = (TextBox)gvRow.FindControl("ProductName");
            DropDownList categories = 
                (DropDownList)gvRow.FindControl("Categories");
            TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
            CheckBox discontinued = 
                (CheckBox)gvRow.FindControl("Discontinued");
            // Assign the user-entered values to the current ProductRow
            product.ProductName = productName.Text.Trim();
            if (categories.SelectedIndex == 0) 
                product.SetCategoryIDNull(); 
            else 
                product.CategoryID = Convert.ToInt32(categories.SelectedValue);
            if (unitPrice.Text.Trim().Length == 0) 
                product.SetUnitPriceNull(); 
            else 
                product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
            product.Discontinued = discontinued.Checked;
        }
    }
    // Now have the BLL update the products data using a transaction
    productsAPI.UpdateWithTransaction(products);
}

Este método comienza obteniendo todos los productos de nuevo en un ProductsDataTable por medio de una llamada al método de BLL GetProducts. A continuación, enumera la colección de ProductGrid GridViewRows. La Rows colección contiene una GridViewRow instancia para cada fila que se muestra en el GridView. Puesto que mostramos como máximo diez filas por página, la colección Rows GridView no tendrá más de diez elementos.

Para cada fila, ProductID se toma de la colección DataKeys y se selecciona la correspondiente ProductsRow de la colección ProductsDataTable. Los cuatro controles de entrada TemplateField son referenciados programáticamente, y sus valores son asignados a las propiedades de la instancia ProductsRow. Después de que se hayan usado los valores de cada fila de GridView para actualizar ProductsDataTable, se pasa al método UpdateWithTransaction de la BLL que, como vimos en el tutorial anterior, sencillamente llama al método UpdateWithTransaction de la DAL.

El algoritmo de actualización por lotes utilizado para este tutorial actualiza cada fila en el ProductsDataTable que corresponde a una fila en el GridView, independientemente de si se ha cambiado la información del producto. Aunque estas actualizaciones ciegas no suelen ser un problema de rendimiento, pueden provocar registros superfluos si está auditando los cambios en la tabla de base de datos. De nuevo en el tutorial Realización de actualizaciones por lotes hemos explorado una interfaz de actualización por lotes con DataList y se ha agregado código que solo actualizaría los registros que el usuario modificó realmente. No dude en usar las técnicas de Realizar actualizaciones de Batch para actualizar el código de este tutorial, si lo desea.

Nota:

Al enlazar el origen de datos a GridView a través de su etiqueta inteligente, Visual Studio asigna automáticamente los valores de clave principal del origen de datos a la propiedad GridView.DataKeyNames Si no enlazaste ObjectDataSource al GridView a través de la etiqueta inteligente del GridView, como se describe en el paso 1, deberás establecer manualmente la propiedad del GridView denominada DataKeyNames a 'ProductID' para tener acceso al valor ProductID de cada fila a través de la colección DataKeys.

El código usado en BatchUpdate es similar al usado en los métodos de UpdateProduct BLL, la principal diferencia es que en los UpdateProduct métodos solo se recupera una sola ProductRow instancia de la arquitectura. El código que asigna las propiedades de ProductRow es el mismo entre los UpdateProducts métodos y el código dentro del foreach bucle en BatchUpdate, como es el patrón general.

Para completar este tutorial, es necesario invocar el BatchUpdate método cuando se hace clic en cualquiera de los botones Actualizar productos. Cree manejadores de eventos para los Click eventos de estos dos botones y agregue el código siguiente en los manejadores de eventos:

BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message", 
    "alert('The products have been updated.');", true);

En primer lugar, se realiza una llamada a BatchUpdate. A continuación, ClientScript property se usa para insertar JavaScript que mostrará un cuadro de mensaje que lee Los productos se han actualizado.

Dedique un minuto a probar este código. Visite BatchUpdate.aspx a través de un explorador, edite una serie de filas y haga clic en uno de los botones Actualizar productos. Suponiendo que no haya errores de validación de entrada, debería ver un cuadro de mensaje que lee Los productos se han actualizado. Para comprobar la atomicidad de la actualización, considere la posibilidad de agregar una restricción aleatoria CHECK , como una que no permita UnitPrice valores de 1234.56. BatchUpdate.aspxA continuación, edite una serie de registros, asegurándose de establecer uno de los valores del UnitPrice producto en el valor prohibido ( 1234.56 ). Esto debería producir un error al hacer clic en Actualizar productos, y que los demás cambios en esa operación por lotes reviertan a sus valores originales.

Un método alternativoBatchUpdate

El BatchUpdate método que acabamos de examinar recupera todos los productos del método BLL y GetProducts , a continuación, actualiza solo los registros que aparecen en GridView. Este enfoque es ideal si GridView no usa la paginación, pero si lo hace, puede haber cientos, miles o decenas de miles de productos, pero solo diez filas en GridView. En tal caso, obtener todos los productos de la base de datos solo para modificar 10 de ellos es menor que lo ideal.

Para esos tipos de situaciones, considere la posibilidad de usar el método siguiente BatchUpdateAlternate en su lugar:

private void BatchUpdateAlternate()
{
    // Enumerate the GridView's Rows collection and create a ProductRow
    ProductsBLL productsAPI = new ProductsBLL();
    Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
    foreach (GridViewRow gvRow in ProductsGrid.Rows)
    {
        // Create a new ProductRow instance
        int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
        
        Northwind.ProductsDataTable currentProductDataTable = 
            productsAPI.GetProductByProductID(productID);
        if (currentProductDataTable.Rows.Count > 0)
        {
            Northwind.ProductsRow product = currentProductDataTable[0];
            // Programmatically access the form field elements in the 
            // current GridViewRow
            TextBox productName = (TextBox)gvRow.FindControl("ProductName");
            DropDownList categories = 
                (DropDownList)gvRow.FindControl("Categories");
            TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
            CheckBox discontinued = 
                (CheckBox)gvRow.FindControl("Discontinued");
            // Assign the user-entered values to the current ProductRow
            product.ProductName = productName.Text.Trim();
            if (categories.SelectedIndex == 0) 
                product.SetCategoryIDNull(); 
            else 
                product.CategoryID = Convert.ToInt32(categories.SelectedValue);
            if (unitPrice.Text.Trim().Length == 0) 
                product.SetUnitPriceNull(); 
            else 
                product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
            product.Discontinued = discontinued.Checked;
            // Import the ProductRow into the products DataTable
            products.ImportRow(product);
        }
    }
    // Now have the BLL update the products data using a transaction
    productsAPI.UpdateProductsWithTransaction(products);
}

BatchMethodAlternate comienza creando un nuevo ProductsDataTable vacío denominado products. A continuación, recorre la colección GridView s Rows y para cada fila obtiene la información de producto concreta mediante el método BLL s GetProductByProductID(productID) . La instancia recuperada ProductsRow tiene sus propiedades actualizadas de la misma manera que BatchUpdate, pero después de actualizar la fila, se importa en products``ProductsDataTable a través del método ImportRow(DataRow) de la DataTable .

Una vez completado el foreach bucle, products contiene una ProductsRow instancia para cada fila de GridView. Puesto que cada una de las ProductsRow instancias se ha agregado a products (en lugar de actualizarse), si las pasamos ciegamente al método UpdateWithTransaction, ProductsTableAdapter intentará insertar cada uno de los registros en la base de datos. En su lugar, es necesario especificar que se ha modificado cada una de estas filas (no se ha agregado).

Esto se puede lograr agregando un nuevo método al BLL denominado UpdateProductsWithTransaction. UpdateProductsWithTransaction, que se muestra a continuación, establece el RowState de cada una de las ProductsRow instancias en ProductsDataTable a Modified y, a continuación, pasa el ProductsDataTable al método de UpdateWithTransaction de DAL.

public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
    // Mark each product as Modified
    products.AcceptChanges();
    foreach (Northwind.ProductsRow product in products)
        product.SetModified();
    // Update the data via a transaction
    return UpdateWithTransaction(products);
}

Resumen

GridView proporciona funcionalidades de edición integradas por fila, pero no admite la creación de interfaces totalmente editables. Como vimos en este tutorial, estas interfaces son posibles, pero requieren un poco de trabajo. Para crear una clase GridView en la que se pueda editar cada fila, es necesario convertir los campos de GridView en TemplateFields y definir la interfaz de edición dentro de los ItemTemplate s. Además, actualizar todos los controles web de botón de -type debe agregarse a la página, aparte de GridView. Estos controladores de eventos de botones Click deben enumerar la colección de GridView Rows, almacenar los cambios en una ProductsDataTable, y pasar la información actualizada al método BLL adecuado.

En el siguiente tutorial veremos cómo crear una interfaz para la eliminación por lotes. En concreto, cada fila de GridView incluirá una casilla de verificación y, en lugar de los botones "Actualizar Todo -type", tendremos botones "Eliminar filas seleccionadas".

¡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 en 24 horas. Se le puede contactar en mitchell@4GuysFromRolla.com.

Agradecimientos especiales a

Esta serie de tutoriales fue revisada por muchos revisores de gran ayuda. Los revisores principales de este tutorial fueron Teresa Murphy y David Suru. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, mándame un mensaje a mitchell@4GuysFromRolla.com.