Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
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.
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
.
Figura 2: Configurar objectDataSource para usar la clase (ProductsBLL
imagen de tamaño completo)
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.
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
, CategoryName
y ) y UnitPrice
un 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.
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 Discontinued
Editar
La creación de las ProductName
interfaces de edición , UnitPrice
y 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.
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 UnitPrice
ItemTemplate
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 GreaterThanEqual
y su ValueToCompare
propiedad en 0 .
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 deCategoryName
edició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 CategoryName
ItemTemplate
, 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
.
Figura 8: Configurar objectDataSource para usar la clase (CategoriesBLL
imagen de tamaño completo)
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.
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.
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.
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.
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.
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.
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.
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.aspx
A 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.