Compartir a través de


Realizar actualizaciones por lotes (C#)

de Scott Mitchell

Descargar PDF

Obtenga información sobre cómo crear una lista de datos totalmente editable donde todos sus elementos están en modo de edición y cuyos valores se pueden guardar haciendo clic en un botón "Actualizar todo" en la página.

Introducción

En el tutorial anterior se ha examinado cómo crear una lista de datos de nivel de elemento. Al igual que el GridView editable estándar, cada elemento en el DataList incluía un botón Editar que, al hacer clic, permitiría que el elemento fuese editable. Aunque esta edición de nivel de elemento funciona bien para los datos que solo se actualizan ocasionalmente, algunos escenarios de casos de uso requieren que el usuario edite muchos registros. Si un usuario necesita editar docenas de registros y se ve obligado a hacer clic en Editar, realizar sus cambios y hacer clic en Actualizar para cada uno, la cantidad de clic puede dificultar su productividad. En tales situaciones, una mejor opción es proporcionar una lista de datos totalmente editable, una donde todos sus elementos están en modo de edición y cuyos valores se pueden editar haciendo clic en un botón Actualizar todo en la página (vea la figura 1).

Cada elemento de una lista de datos totalmente editable se puede modificar.

Figura 1: Cada elemento de una lista de datos totalmente editable se puede modificar (hacer clic para ver la imagen de tamaño completo)

En este tutorial, examinaremos cómo permitir que los usuarios actualicen la información de direcciones de los proveedores mediante dataList totalmente editable.

Paso 1: Crear la interfaz de usuario editable en ItemTemplate de DataList

En el tutorial anterior, donde creamos un DataList estándar de nivel de elemento editable, usamos dos plantillas:

  • ItemTemplate contenía la interfaz de usuario de solo lectura (los controles Web Label para mostrar el nombre y el precio de cada producto).
  • EditItemTemplate contenía la interfaz de usuario del modo de edición (los dos controles web TextBox).

La propiedad DataList EditItemIndex determina qué DataListItem(si existe) se representa con el uso de EditItemTemplate. En particular, el DataListItem, cuyo valor ItemIndex coincide con la propiedad EditItemIndex del DataList, se representa utilizando el EditItemTemplate. Este modelo funciona bien cuando solo se puede editar un elemento a la vez, pero se desmorona cuando se crea una lista de datos totalmente editable.

Para un objeto DataList totalmente editable, queremos que todos losDataListItem elementos se representen mediante la interfaz editable. La manera más sencilla de lograrlo es definir la interfaz editable en .ItemTemplate Para modificar la información de dirección de los proveedores, la interfaz editable contiene el nombre del proveedor como texto y, a continuación, TextBoxes para los valores de dirección, ciudad y país o región.

Para empezar, abra la BatchUpdate.aspx página, agregue un control DataList y establezca su propiedad ID a Suppliers. En la etiqueta inteligente DataList, opte por agregar un nuevo control ObjectDataSource denominado SuppliersDataSource.

Crear un nuevo ObjectDataSource denominado SuppliersDataSource

Figura 2: Crear un nuevo objetoDataSource denominado SuppliersDataSource (haga clic para ver la imagen de tamaño completo)

Configure el ObjectDataSource para recuperar datos mediante la clase SuppliersBLL y el método GetSuppliers() (vea la Figura 3). Al igual que con el tutorial anterior, en lugar de actualizar la información del proveedor a través de ObjectDataSource, trabajaremos directamente con la capa de lógica de negocios. Por lo tanto, establezca la lista desplegable en (Ninguno) en la pestaña UPDATE (vea la figura 4).

Recuperar información de proveedor mediante el método GetSuppliers()

Figura 3: Recuperar información de proveedor mediante el método (GetSuppliers() la imagen de tamaño completo)

Establezca la lista de Drop-Down en (Ninguno) en la pestaña UPDATE

Figura 4: Establecer la lista de Drop-Down en (Ninguno) en la pestaña UPDATE (haga clic para ver la imagen de tamaño completo)

Después de completar el asistente, Visual Studio genera automáticamente el DataList ItemTemplate para mostrar cada campo de datos devuelto por el origen de datos en un control web Label. Es necesario modificar esta plantilla para que proporcione la interfaz de edición en su lugar. El ItemTemplate se puede personalizar a través del Diseñador mediante la opción Editar plantillas de la etiqueta inteligente de DataList o directamente a través de la sintaxis declarativa.

Dedique un momento a crear una interfaz de edición que muestre el nombre del proveedor como texto, pero incluya textBoxes para los valores de dirección, ciudad y país o región del proveedor. Después de realizar estos cambios, la sintaxis declarativa de la página debe ser similar a la siguiente:

<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID"
    DataSourceID="SuppliersDataSource">
    <ItemTemplate>
        <h4><asp:Label ID="CompanyNameLabel" runat="server"
            Text='<%# Eval("CompanyName") %>' /></h4>
        <table border="0">
            <tr>
                <td class="SupplierPropertyLabel">Address:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Address" runat="server"
                        Text='<%# Eval("Address") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">City:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="City" runat="server"
                        Text='<%# Eval("City") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">Country:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Country" runat="server"
                        Text='<%# Eval("Country") %>' />
                </td>
            </tr>
        </table>
        <br />
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>

Nota:

Al igual que con el tutorial anterior, dataList de este tutorial debe tener habilitado su estado de vista.

En el ItemTemplate, estoy utilizando dos nuevas clases CSS, SupplierPropertyLabel y SupplierPropertyValue, que han sido añadidas a la clase Styles.css y configuradas para usar la misma configuración de estilo que las clases CSS ProductPropertyLabel y ProductPropertyValue.

.ProductPropertyLabel, .SupplierPropertyLabel
{
    font-weight: bold;
    text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
    padding-right: 35px;
}

Después de realizar estos cambios, visite esta página a través de un explorador. Como se muestra en la figura 5, cada elemento DataList muestra el nombre del proveedor como texto y usa TextBoxes para mostrar la dirección, la ciudad y el país o región.

Cada proveedor en la lista de datos es editable

Figura 5: Cada proveedor de la lista de datos es editable (haga clic para ver la imagen de tamaño completo)

Paso 2: Agregar un botón Actualizar todo

Aunque cada proveedor de la figura 5 tiene sus campos de dirección, ciudad y país o región mostrados en un TextBox, actualmente no hay ningún botón Actualizar disponible. En lugar de tener un botón Actualizar por elemento, con listas de datos totalmente editables, normalmente hay un solo botón Actualizar todo en la página que, cuando se hace clic, actualiza todos los registros de la lista de datos. En este tutorial, vamos a agregar dos botones Actualizar todo: uno en la parte superior de la página y otro en la parte inferior (aunque hacer clic en cualquiera de los botones tendrá el mismo efecto).

Empiece por agregar un control web Botón encima del DataList y establezca su propiedad ID en UpdateAll1. A continuación, agregue el segundo control Web de botón debajo de DataList, estableciendo su propiedad en IDUpdateAll2. Establezca las Text propiedades de los dos botones en Actualizar todo. Por último, crea controladores de eventos para los eventos de ambos botones Click. En lugar de duplicar la lógica de actualización en cada uno de los controladores de eventos, refactoricemos esa lógica en un tercer método, UpdateAllSupplierAddresses, teniendo los controladores de eventos simplemente invocando este tercer método.

protected void UpdateAll1_Click(object sender, EventArgs e)
{
    UpdateAllSupplierAddresses();
}
protected void UpdateAll2_Click(object sender, EventArgs e)
{
    UpdateAllSupplierAddresses();
}
private void UpdateAllSupplierAddresses()
{
    // TODO: Write code to update _all_ of the supplier addresses in the DataList
}

En la figura 6 se muestra la página después de agregar los botones Actualizar todo.

Se han agregado dos botones de actualización a la página

Figura 6: Se han agregado dos botones actualizar todos a la página (haga clic para ver la imagen de tamaño completo)

Paso 3: Actualizar toda la información de direcciones de proveedores

Con todos los elementos de DataList que muestran la interfaz de edición y con la adición de los botones Actualizar todo, todo lo que permanece es escribir el código para realizar la actualización por lotes. En concreto, es necesario recorrer en bucle los elementos de DataList y llamar al método de la SuppliersBLL clase s UpdateSupplierAddress para cada uno.

Se puede acceder a la colección de instancias que componen el DataList a través de la propiedad DataListItem DataList Items. Con una referencia a DataListItem, podemos obtener el correspondiente SupplierID en la colección DataKeys y referenciar de manera programática los controles de texto Web TextBox dentro de ItemTemplate, como se muestra en el código siguiente:

private void UpdateAllSupplierAddresses()
{
    // Create an instance of the SuppliersBLL class
    SuppliersBLL suppliersAPI = new SuppliersBLL();
    // Iterate through the DataList's items
    foreach (DataListItem item in Suppliers.Items)
    {
        // Get the supplierID from the DataKeys collection
        int supplierID = Convert.ToInt32(Suppliers.DataKeys[item.ItemIndex]);
        // Read in the user-entered values
        TextBox address = (TextBox)item.FindControl("Address");
        TextBox city = (TextBox)item.FindControl("City");
        TextBox country = (TextBox)item.FindControl("Country");
        string addressValue = null, cityValue = null, countryValue = null;
        if (address.Text.Trim().Length > 0)
            addressValue = address.Text.Trim();
        if (city.Text.Trim().Length > 0)
              cityValue = city.Text.Trim();
        if (country.Text.Trim().Length > 0)
            countryValue = country.Text.Trim();
        // Call the SuppliersBLL class's UpdateSupplierAddress method
        suppliersAPI.UpdateSupplierAddress
            (supplierID, addressValue, cityValue, countryValue);
    }
}

Cuando el usuario hace clic en uno de los botones Actualizar todo, el UpdateAllSupplierAddresses método recorre en iteración cada DataListItem en la Suppliers DataList y llama al método de la clase SuppliersBLLUpdateSupplierAddress, pasando los valores correspondientes. Un valor no ingresado para dirección, ciudad o país/región tiene un valor de Nothing a UpdateSupplierAddress (en lugar de una cadena en blanco), lo que resulta en un tratamiento NULL para los campos del registro subyacente en la base de datos.

Nota:

Como mejora, puede que desee agregar un control web de etiqueta de estado a la página que proporcione un mensaje de confirmación después de realizar la actualización por lotes.

Actualizar solo las direcciones que se han modificado

El algoritmo de actualización por lotes usado para este tutorial llama al UpdateSupplierAddress método para cada proveedor de DataList, independientemente de si se ha cambiado su información de dirección. 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. Por ejemplo, si usa desencadenadores para registrar todos los UPDATE elementos de la Suppliers tabla en una tabla de auditoría, cada vez que un usuario hace clic en el botón Actualizar todo, se creará un nuevo registro de auditoría para cada proveedor del sistema, independientemente de si el usuario realizó algún cambio.

Las clases dataTable y DataAdapter de ADO.NET están diseñadas para admitir actualizaciones por lotes en las que solo se modifican, eliminan y se producen nuevos registros en cualquier comunicación de base de datos. Cada fila de DataTable tiene una RowState propiedad que indica si la fila se ha agregado a La Tabla de datos, se eliminó de ella, modificó o permanece sin cambios. Cuando se rellena inicialmente una Tabla de datos, todas las filas se marcan sin cambios. Cambiar el valor en cualquiera de las columnas de la fila marca la fila como modificada.

En la SuppliersBLL clase, actualizamos la información de la dirección del proveedor especificado leyendo primero el registro del proveedor único en SuppliersDataTable y luego establecemos los valores de las columnas Address, City y Country mediante el código siguiente:

public bool UpdateSupplierAddress
    (int supplierID, string address, string city, string country)
{
    Northwind.SuppliersDataTable suppliers =
        Adapter.GetSupplierBySupplierID(supplierID);
    if (suppliers.Count == 0)
        // no matching record found, return false
        return false;
    else
    {
        Northwind.SuppliersRow supplier = suppliers[0];
        if (address == null)
            supplier.SetAddressNull();
        else
            supplier.Address = address;
        if (city == null)
            supplier.SetCityNull();
        else
            supplier.City = city;
        if (country == null)
            supplier.SetCountryNull();
        else
            supplier.Country = country;
        // Update the supplier Address-related information
        int rowsAffected = Adapter.Update(supplier);
        // Return true if precisely one row was updated,
        // otherwise false
        return rowsAffected == 1;
    }
}

Este código asigna sin considerar los valores de dirección, ciudad y país y/o región pasados a SuppliersRow en el SuppliersDataTable, independientemente de si los valores han cambiado o no. Estas modificaciones hacen que la SuppliersRow propiedad s RowState se marque como modificada. Cuando se llama al método de la capa de acceso a datos Update, ve que SupplierRow se ha modificado y, por tanto, envía un comando UPDATE a la base de datos.

Sin embargo, imagine que agregamos código a este método para únicamente asignar los valores de dirección, ciudad y país o región proporcionados, si estos difieren de los valores existentes de SuppliersRow. En el caso de que la dirección, la ciudad y el país o región sean los mismos que los datos existentes, no se realizará ningún cambio y los SupplierRow valores RowState se dejarán marcados como sin cambios. El resultado neto es que cuando se llama al método dal Update , no se realizará ninguna llamada a base de datos porque SuppliersRow no se ha modificado .

Para aplicar este cambio, reemplace las instrucciones que asignan ciegamente los valores de dirección, ciudad y país o región pasados por el código siguiente:

// Only assign the values to the SupplierRow's column values if they differ
if (address == null && !supplier.IsAddressNull())
    supplier.SetAddressNull();
else if ((address != null && supplier.IsAddressNull()) ||
         (!supplier.IsAddressNull() &&
         string.Compare(supplier.Address, address) != 0))
    supplier.Address = address;
if (city == null && !supplier.IsCityNull())
    supplier.SetCityNull();
else if ((city != null && supplier.IsCityNull()) ||
         (!supplier.IsCityNull() && string.Compare(supplier.City, city) != 0))
    supplier.City = city;
if (country == null && !supplier.IsCountryNull())
    supplier.SetCountryNull();
else if ((country != null && supplier.IsCountryNull()) ||
         (!supplier.IsCountryNull() &&
         string.Compare(supplier.Country, country) != 0))
    supplier.Country = country;

Con este código agregado, el método dal Update envía una UPDATE instrucción a la base de datos solo para aquellos registros cuyos valores relacionados con la dirección han cambiado.

Como alternativa, podríamos realizar un seguimiento de si hay diferencias entre los campos de dirección pasados y los datos de la base de datos. Si no las hay, simplemente omitimos la llamada al método Update del DAL. Este enfoque funciona bien si usa el método directo de base de datos, ya que el método directo de base de datos no se pasa a una SuppliersRow instancia cuya RowState instancia se puede comprobar para determinar si realmente se necesita una llamada de base de datos.

Nota:

Cada vez que se invoca el UpdateSupplierAddress método , se realiza una llamada a la base de datos para recuperar información sobre el registro actualizado. A continuación, si hay algún cambio en los datos, se realiza otra llamada a la base de datos para actualizar la fila de la tabla. Este flujo de trabajo podría optimizarse mediante la creación de una UpdateSupplierAddress sobrecarga de método que acepte una EmployeesDataTable instancia que tenga todos los cambios de la BatchUpdate.aspx página. A continuación, podría realizar una llamada a la base de datos para obtener todos los registros de la Suppliers tabla. Los dos conjuntos de resultados se podrían enumerar y solo se podrían actualizar los registros en los que se han producido cambios.

Resumen

En este tutorial hemos visto cómo crear una lista de datos totalmente editable, lo que permite a un usuario modificar rápidamente la información de dirección de varios proveedores. Empezamos definiendo la interfaz de edición un control web TextBox para los valores de dirección, ciudad y región del proveedor en DataList s ItemTemplate. A continuación, hemos agregado el botón de Actualizar Todo encima y debajo de la Lista de Datos. Una vez que un usuario ha realizado sus cambios y ha hecho clic en uno de los botones Actualizar todo, se enumeran los DataListItem s y se realiza una llamada al método de la SuppliersBLL clase s UpdateSupplierAddress .

¡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 puede contactar a 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 Zack Jones y Ken Pespisa. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, escríbeme en mitchell@4GuysFromRolla.com.