Atualização em lote (C#)
por Scott Mitchell
Saiba como atualizar vários registros de banco de dados em uma única operação. Na Camada de Interface do Usuário, criamos um GridView em que cada linha é editável. Na Camada de Acesso a Dados, encapsulamos as várias operações de Atualização dentro de uma transação para garantir que todas as atualizações sejam bem-sucedidas ou todas as atualizações sejam revertidas.
Introdução
No tutorial anterior , vimos como estender a Camada de Acesso a Dados para adicionar suporte a transações de banco de dados. As transações de banco de dados garantem que uma série de instruções de modificação de dados será tratada como uma operação atômica, o que garante que todas as modificações falharão ou todas terão êxito. Com essa funcionalidade de DAL de baixo nível fora do caminho, estamos prontos para voltar nossa atenção para a criação de interfaces de modificação de dados em lote.
Neste tutorial, criaremos um GridView em que cada linha é editável (consulte a Figura 1). Como cada linha é renderizada em sua interface de edição, não há necessidade de uma coluna dos botões Editar, Atualizar e Cancelar. Em vez disso, há dois botões Atualizar Produtos na página que, quando clicados, enumeram as linhas GridView e atualizam o banco de dados.
Figura 1: cada linha no GridView é editável (clique para exibir a imagem em tamanho real)
Vamos começar!
Observação
No tutorial Executando o Lote Atualizações criamos uma interface de edição em lote usando o controle DataList. Este tutorial difere do anterior em que usa um GridView e a atualização em lote é executada dentro do escopo de uma transação. Depois de concluir este tutorial, encorajo você a retornar ao tutorial anterior e atualizá-lo para usar a funcionalidade relacionada à transação de banco de dados adicionada no tutorial anterior.
Examinando as etapas para tornar todas as linhas gridView editáveis
Conforme discutido no tutorial Uma visão geral de inserção, atualização e exclusão de dados , o GridView oferece suporte interno para editar seus dados subjacentes por linha. Internamente, GridView observa qual linha é editável por meio de sua EditIndex
propriedade. Como o GridView está sendo associado à sua fonte de dados, ele verifica cada linha para ver se o índice da linha é igual ao valor de EditIndex
. Nesse caso, esses campos de linhas são renderizados usando suas interfaces de edição. Para BoundFields, a interface de edição é uma TextBox cuja Text
propriedade é atribuída ao valor do campo de dados especificado pela propriedade BoundField s DataField
. Para TemplateFields, o EditItemTemplate
é usado no lugar do ItemTemplate
.
Lembre-se de que o fluxo de trabalho de edição é iniciado quando um usuário clica no botão Editar de uma linha. Isso causa um postback, define a propriedade gridView como EditIndex
o índice de linhas clicadas e reassocia os dados à grade. Quando um botão Cancelar de uma linha é clicado, no postback o EditIndex
é definido como um valor de antes de -1
reassociar os dados à grade. Como as linhas do GridView começam a indexar em zero, a configuração como EditIndex
-1
tem o efeito de exibir o GridView no modo somente leitura.
A EditIndex
propriedade funciona bem para edição por linha, mas não foi projetada para edição em lote. Para tornar todo o GridView editável, precisamos ter cada linha renderizada usando sua interface de edição. A maneira mais fácil de fazer isso é criar onde cada campo editável é implementado como um TemplateField com sua interface de edição definida no ItemTemplate
.
Nas próximas etapas, criaremos um GridView completamente editável. Na Etapa 1, começaremos criando o GridView e seu ObjectDataSource e convertendo boundFields e CheckBoxField em TemplateFields. Nas Etapas 2 e 3, moveremos as interfaces de edição dos TemplateFields EditItemTemplate
para seus ItemTemplate
s.
Etapa 1: Exibindo informações do produto
Antes de nos preocuparmos em criar um GridView em que as linhas são editáveis, vamos começar simplesmente exibindo as informações do produto. Abra a BatchUpdate.aspx
página na BatchData
pasta e arraste um GridView da Caixa de Ferramentas para o Designer. Defina o GridView s ID
como ProductsGrid
e, de sua marca inteligente, escolha associá-lo a um novo ObjectDataSource chamado ProductsDataSource
. Configure o ObjectDataSource para recuperar seus dados do ProductsBLL
método da classe s GetProducts
.
Figura 2: Configurar o ObjectDataSource para usar a ProductsBLL
classe (clique para exibir a imagem em tamanho real)
Figura 3: Recuperar os dados do produto usando o GetProducts
método (clique para exibir a imagem em tamanho real)
Assim como o GridView, os recursos de modificação do ObjectDataSource são projetados para funcionar por linha. Para atualizar um conjunto de registros, precisaremos escrever um pouco de código na classe code-behind da página ASP.NET que agrupa os dados e os passa para a BLL. Portanto, defina as listas suspensas nas guias UPDATE, INSERT e DELETE do ObjectDataSource como (Nenhum). Clique em Concluir para concluir o assistente.
Figura 4: Definir o Drop-Down Listas nas guias UPDATE, INSERT e DELETE como (Nenhum) (Clique para exibir a imagem em tamanho real)
Depois de concluir o assistente Configurar Fonte de Dados, a marcação declarativa do ObjectDataSource deverá ser semelhante à seguinte:
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
A conclusão do assistente Configurar Fonte de Dados também faz com que o Visual Studio crie BoundFields e um CheckBoxField para os campos de dados do produto no GridView. Para este tutorial, vamos permitir apenas que o usuário exiba e edite o nome, a categoria, o preço e os status descontinuados do produto. Remova todos, exceto os ProductName
campos , CategoryName
, UnitPrice
e Discontinued
e renomeie as HeaderText
propriedades dos três primeiros campos como Produto, Categoria e Preço, respectivamente. Por fim, marcar as caixas de seleção Habilitar Paginação e Habilitar Classificação na marca inteligente GridView.
Neste ponto, o GridView tem três BoundFields (ProductName
, CategoryName
e UnitPrice
) e um CheckBoxField (Discontinued
). Precisamos converter esses quatro campos em TemplateFields e, em seguida, mover a interface de edição do TemplateField s EditItemTemplate
para seu ItemTemplate
.
Observação
Exploramos a criação e a personalização de TemplateFields no tutorial Personalizando a Interface de Modificação de Dados . Vamos percorrer as etapas de conversão de BoundFields e CheckBoxField em TemplateFields e definição de suas interfaces de edição em seus ItemTemplate
s, mas se você ficar preso ou precisar de um atualizador, não hesite em fazer referência a este tutorial anterior.
Na marca inteligente GridView, clique no link Editar Colunas para abrir a caixa de diálogo Campos. Em seguida, selecione cada campo e clique no link Converter este campo em um TemplateField.
Figura 5: Converter BoundFields e CheckBoxField existentes em TemplateField
Agora que cada campo é um TemplateField, estamos prontos para mover a interface de edição dos EditItemTemplate
s para os ItemTemplate
s.
Etapa 2: Criando asProductName
UnitPrice
interfaces de edição eDiscontinued
Criar as ProductName
interfaces de edição , UnitPrice
e Discontinued
são o tópico desta etapa e são bastante simples, pois cada interface já está definida no TemplateField s EditItemTemplate
. A criação da CategoryName
interface de edição é um pouco mais envolvida, pois precisamos criar uma DropDownList das categorias aplicáveis. Essa CategoryName
interface de edição é abordada na Etapa 3.
Vamos começar com TemplateField ProductName
. Clique no link Editar Modelos da marca inteligente GridView e faça drill down até TemplateField ProductName
s EditItemTemplate
. Selecione TextBox, copie-o para a área de transferência e cole-o no ProductName
TemplateField s ItemTemplate
. Altere a propriedade textBox s ID
para ProductName
.
Em seguida, adicione um RequiredFieldValidator ao ItemTemplate
para garantir que o usuário forneça um valor para cada nome de produto. Defina a ControlToValidate
propriedade como ProductName, a ErrorMessage
propriedade como Você deve fornecer o nome do produto. e a Text
propriedade para *. Depois de fazer essas adições ao ItemTemplate
, sua tela deve ser semelhante à Figura 6.
Figura 6: O ProductName
TemplateField agora inclui uma TextBox e um RequiredFieldValidator (clique para exibir a imagem em tamanho real)
Para a UnitPrice
interface de edição, comece copiando TextBox do EditItemTemplate
para o ItemTemplate
. Em seguida, coloque um $ na frente da TextBox e defina sua ID
propriedade como UnitPrice e sua Columns
propriedade como 8 .
Adicione também um CompareValidator aos UnitPrice
s ItemTemplate
para garantir que o valor inserido pelo usuário seja um valor de moeda válido maior ou igual a US$ 0,00. Defina a propriedade do validador como ControlToValidate
UnitPrice, sua propriedade como ErrorMessage
Você deve inserir um valor de moeda válido. Omita todos os símbolos de moeda, sua Text
propriedade para *, sua Type
propriedade para Currency
, sua Operator
propriedade para GreaterThanEqual
e sua ValueToCompare
propriedade como 0 .
Figura 7: Adicionar um CompareValidator para garantir que o preço inserido seja um valor de Conversor de Moedas não negativo (clique para exibir a imagem em tamanho real)
Para o Discontinued
TemplateField, você pode usar a CheckBox já definida no ItemTemplate
. Basta definir como ID
Descontinuado e sua Enabled
propriedade como true
.
Etapa 3: Criando aCategoryName
interface de edição
A interface de edição no CategoryName
TemplateField s EditItemTemplate
contém um TextBox que exibe o valor do campo de CategoryName
dados. Precisamos substituir isso por um DropDownList que lista as categorias possíveis.
Observação
O tutorial Personalizando a Interface de Modificação de Dados contém uma discussão mais completa e completa sobre como personalizar um modelo para incluir um DropDownList em vez de um TextBox. Embora as etapas aqui estejam concluídas, elas são apresentadas com tersely. Para obter uma visão mais detalhada sobre como criar e configurar as categorias DropDownList, consulte o tutorial Personalizando a Interface de Modificação de Dados .
Arraste um DropDownList da Caixa de Ferramentas para o TemplateField s , definindo-o CategoryName
ID
como Categories
.ItemTemplate
Neste ponto, normalmente definiríamos a fonte de dados do DropDownLists por meio de sua marca inteligente, criando um novo ObjectDataSource. No entanto, isso adicionará ObjectDataSource no , o ItemTemplate
que resultará em uma instância ObjectDataSource criada para cada linha GridView. Em vez disso, vamos criar o ObjectDataSource fora dos TemplateFields do GridView. Encerre a edição do modelo e arraste um ObjectDataSource da Caixa de Ferramentas para a Designer abaixo do ProductsDataSource
ObjectDataSource. Nomeie o novo ObjectDataSource CategoriesDataSource
e configure-o para usar o CategoriesBLL
método da classe s GetCategories
.
Figura 8: Configurar o ObjectDataSource para usar a CategoriesBLL
classe (Clique para exibir a imagem em tamanho real)
Figura 9: recuperar os dados de categoria usando o GetCategories
método (clique para exibir a imagem em tamanho real)
Como este ObjectDataSource é usado apenas para recuperar dados, defina as listas suspensas nas guias UPDATE e DELETE como (Nenhum). Clique em Concluir para concluir o assistente.
Figura 10: defina o Drop-Down Listas nas guias UPDATE e DELETE como (Nenhum) (Clique para exibir a imagem em tamanho real)
Depois de concluir o assistente, a CategoriesDataSource
marcação declarativa do s deve ser semelhante à seguinte:
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Com o CategoriesDataSource
criado e configurado, retorne ao CategoryName
TemplateField s ItemTemplate
e, na marca inteligente DropDownList, clique no link Escolher Fonte de Dados. No assistente Configuração da Fonte de Dados, selecione a opção CategoriesDataSource
na primeira lista suspensa e escolha ter CategoryName
usado para a exibição e CategoryID
como o valor.
Figura 11: Associar o DropDownList ao CategoriesDataSource
(Clique para exibir a imagem em tamanho real)
Neste ponto, o Categories
DropDownList lista todas as categorias, mas ainda não seleciona automaticamente a categoria apropriada para o produto associado à linha GridView. Para fazer isso, precisamos definir o Categories
DropDownList s SelectedValue
para o valor do CategoryID
produto. Clique no link Editar DataBindings da marca inteligente DropDownList e associe a SelectedValue
propriedade ao CategoryID
campo de dados, conforme mostrado na Figura 12.
Figura 12: Associar o valor do CategoryID
produto à propriedade DropDownList s SelectedValue
Um último problema permanece: se o produto não tiver um CategoryID
valor especificado, a instrução de vinculação de dados em SelectedValue
resultará em uma exceção. Isso ocorre porque o DropDownList contém apenas itens para as categorias e não oferece uma opção para os produtos que têm um NULL
valor de banco de dados para CategoryID
. Para corrigir isso, defina a propriedade true
dropDownList como AppendDataBoundItems
e adicione um novo item ao DropDownList, omitindo a Value
propriedade da sintaxe declarativa. Ou seja, verifique se a Categories
sintaxe declarativa do DropDownList é semelhante à seguinte:
<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>
Observe como o <asp:ListItem Value="">
-- Select One -- tem seu Value
atributo definido explicitamente como uma cadeia de caracteres vazia. Consulte o tutorial Personalizando a Interface de Modificação de Dados para obter uma discussão mais detalhada sobre por que esse item DropDownList adicional é necessário para lidar com o NULL
caso e por que a Value
atribuição da propriedade a uma cadeia de caracteres vazia é essencial.
Observação
Há um possível problema de desempenho e escalabilidade aqui que vale a pena mencionar. Como cada linha tem um DropDownList que usa o CategoriesDataSource
como sua fonte de dados, o CategoriesBLL
método de classe s GetCategories
será chamado n vezes por visita de página, em que n é o número de linhas no GridView. Essas n chamadas para GetCategories
resultar em n consultas para o banco de dados. Esse impacto no banco de dados pode ser diminuído armazenando em cache as categorias retornadas em um cache por solicitação ou por meio da Camada de Cache usando uma dependência de cache SQL ou uma expiração baseada em tempo muito curta.
Etapa 4: Concluindo a interface de edição
Fizemos várias alterações nos modelos do GridView sem pausar para ver nosso progresso. Reserve um momento para ver nosso progresso por meio de um navegador. Como mostra a Figura 13, cada linha é renderizada usando seu ItemTemplate
, que contém a interface de edição da célula.
Figura 13: cada linha gridview é editável (clique para exibir imagem em tamanho real)
Há alguns pequenos problemas de formatação que devemos cuidar neste momento. Primeiro, observe que o UnitPrice
valor contém quatro pontos decimais. Para corrigir isso, retorne ao UnitPrice
TemplateField s ItemTemplate
e, na marca inteligente TextBox, clique no link Editar DataBindings. Em seguida, especifique que a Text
propriedade deve ser formatada como um número.
Figura 14: formatar a Text
propriedade como um número
Em segundo lugar, vamos centralizar a caixa de seleção na Discontinued
coluna (em vez de tê-la alinhada à esquerda). Clique em Editar Colunas na marca inteligente GridView e selecione TemplateField Discontinued
na lista de campos no canto inferior esquerdo. Faça uma busca detalhada ItemStyle
e defina a HorizontalAlign
propriedade como Central, conforme mostrado na Figura 15.
Figura 15: Centralizar a Caixa de Seleção Discontinued
Em seguida, adicione um controle ValidationSummary à página e defina sua ShowMessageBox
propriedade como true
e sua ShowSummary
propriedade como false
. Adicione também os controles Da Web de Botão que, quando clicados, atualizarão as alterações do usuário. Especificamente, adicione dois controles Web button, um acima do GridView e outro abaixo dele, definindo ambas as propriedades de controles Text
como Atualizar Produtos.
Como a interface de edição do GridView é definida em seus TemplateFields ItemTemplate
s, os EditItemTemplate
s são supérfluos e podem ser excluídos.
Depois de fazer as alterações de formatação mencionadas acima, adicionar os controles Button e remover os s desnecessários EditItemTemplate
, a sintaxe declarativa da página deve ser semelhante à seguinte:
<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>
A Figura 16 mostra essa página quando exibida por meio de um navegador após a adição dos controles da Web de botão e as alterações de formatação feitas.
Figura 16: a página agora inclui dois botões de produtos de atualização (clique para exibir a imagem em tamanho real)
Etapa 5: Atualizando os produtos
Quando um usuário visita esta página, ele fará suas modificações e, em seguida, clicará em um dos dois botões Atualizar Produtos. Nesse ponto, precisamos de alguma forma salvar os valores inseridos pelo usuário para cada linha em uma ProductsDataTable
instância e, em seguida, passá-los para um método BLL que, em seguida, passará essa ProductsDataTable
instância para o método da DAL s UpdateWithTransaction
. O UpdateWithTransaction
método, que criamos no tutorial anterior, garante que o lote de alterações seja atualizado como uma operação atômica.
Crie um método chamado BatchUpdate
em BatchUpdate.aspx.cs
e adicione o seguinte código:
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);
}
Esse método começa obtendo todos os produtos de volta em um ProductsDataTable
por meio de uma chamada para o método S da GetProducts
BLL. Em seguida, ele enumera a ProductGrid
coleção GridView.Rows
A Rows
coleção contém uma GridViewRow
instância para cada linha exibida no GridView. Como estamos mostrando no máximo dez linhas por página, a coleção GridView Rows
não terá mais de dez itens.
Para cada linha, o ProductID
é capturado da DataKeys
coleção e o apropriado ProductsRow
é selecionado no ProductsDataTable
. Os quatro controles de entrada TemplateField são referenciados programaticamente e seus valores atribuídos às ProductsRow
propriedades da instância. Depois que cada valor de linha GridView tiver sido usado para atualizar o ProductsDataTable
, ele será passado para o método S UpdateWithTransaction
da BLL que, como vimos no tutorial anterior, simplesmente chama para baixo o método da DAL s UpdateWithTransaction
.
O algoritmo de atualização em lote usado para este tutorial atualiza cada linha no ProductsDataTable
que corresponde a uma linha no GridView, independentemente de as informações do produto serem alteradas. Embora essas atualizações cegas geralmente não sejam um problema de desempenho, elas podem levar a registros supérfluos se você estiver auditando alterações na tabela de banco de dados. De volta ao tutorial Executando o Lote Atualizações exploramos uma interface de atualização em lote com a DataList e adicionamos código que atualizaria apenas os registros que foram realmente modificados pelo usuário. Fique à vontade para usar as técnicas de Executar Atualizações do Lote para atualizar o código neste tutorial, se desejado.
Observação
Ao associar a fonte de dados ao GridView por meio de sua marca inteligente, o Visual Studio atribui automaticamente os valores de chave primária da fonte de dados à propriedade GridView DataKeyNames
. Se você não associou ObjectDataSource ao GridView por meio da marca inteligente GridView, conforme descrito na Etapa 1, será necessário definir manualmente a propriedade GridView DataKeyNames
como ProductID para acessar o ProductID
valor de cada linha por meio da DataKeys
coleção.
O código usado em BatchUpdate
é semelhante ao usado nos métodos de UpdateProduct
BLL, a main diferença é que, nos UpdateProduct
métodos, apenas uma única ProductRow
instância é recuperada da arquitetura. O código que atribui as propriedades do ProductRow
é o mesmo entre os UpdateProducts
métodos e o código dentro do foreach
loop em BatchUpdate
, como é o padrão geral.
Para concluir este tutorial, precisamos ter o BatchUpdate
método invocado quando um dos botões Atualizar Produtos for clicado. Crie manipuladores de eventos para os Click
eventos desses dois controles Button e adicione o seguinte código nos manipuladores de eventos:
BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message",
"alert('The products have been updated.');", true);
Primeiro, uma chamada é feita para BatchUpdate
. Em seguida, o ClientScript property
é usado para injetar JavaScript que exibirá uma caixa de mensagem que lê Os produtos foram atualizados.
Tire um minuto para testar esse código. Visite BatchUpdate.aspx
um navegador, edite várias linhas e clique em um dos botões Atualizar Produtos. Supondo que não haja erros de validação de entrada, você deverá ver uma caixa de mensagem que lê Os produtos foram atualizados. Para verificar a atomicidade da atualização, considere adicionar uma restrição aleatória CHECK
, como uma que não permite UnitPrice
valores de 1234,56. Em seguida, em BatchUpdate.aspx
, edite vários registros, certificando-se de definir um dos valores do UnitPrice
produto para o valor proibido ( 1234,56 ). Isso deve resultar em um erro ao clicar em Atualizar Produtos com as outras alterações durante essa operação em lote revertida para seus valores originais.
Um método alternativoBatchUpdate
O BatchUpdate
método que acabamos de examinar recupera todos os produtos do método S da GetProducts
BLL e atualiza apenas os registros que aparecem no GridView. Essa abordagem é ideal se o GridView não usar paginação, mas, se isso acontecer, poderá haver centenas, milhares ou dezenas de milhares de produtos, mas apenas dez linhas no GridView. Nesse caso, obter todos os produtos do banco de dados apenas para modificar 10 deles é menor que o ideal.
Para esses tipos de situações, considere usar o seguinte BatchUpdateAlternate
método em vez disso:
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
começa criando um novo vazio ProductsDataTable
chamado products
. Em seguida, ele percorre a coleção GridView Rows
e, para cada linha, obtém as informações específicas do produto usando o método S da GetProductByProductID(productID)
BLL. A instância recuperada ProductsRow
tem suas propriedades atualizadas da mesma forma BatchUpdate
que , mas depois de atualizar a linha, ela é importada para o products``ProductsDataTable
por meio do método DataTable sImportRow(DataRow)
.
Após a conclusão do foreach
loop, products
contém uma ProductsRow
instância para cada linha no GridView. Como cada uma das ProductsRow
instâncias foi adicionada ao products
(em vez de atualizada), se passarmos cegamente para o UpdateWithTransaction
método , o ProductsTableAdapter
tentará inserir cada um dos registros no banco de dados. Em vez disso, precisamos especificar que cada uma dessas linhas foi modificada (não adicionada).
Isso pode ser feito adicionando um novo método à BLL chamada UpdateProductsWithTransaction
. UpdateProductsWithTransaction
, mostrado abaixo, define o RowState
de cada uma das ProductsRow
instâncias no para Modified
e, em ProductsDataTable
seguida, passa o ProductsDataTable
para o método DAL sUpdateWithTransaction
.
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);
}
Resumo
O GridView fornece recursos internos de edição por linha, mas não tem suporte para criar interfaces totalmente editáveis. Como vimos neste tutorial, essas interfaces são possíveis, mas exigem um pouco de trabalho. Para criar um GridView em que cada linha é editável, precisamos converter os campos do GridView em TemplateFields e definir a interface de edição dentro dos ItemTemplate
s. Além disso, atualizar todos os tipos controles da Web de botão devem ser adicionados à página, separados do GridView. Esses manipuladores de eventos Buttons Click
precisam enumerar a coleção GridView Rows
, armazenar as alterações em um ProductsDataTable
e passar as informações atualizadas para o método BLL apropriado.
No próximo tutorial, veremos como criar uma interface para exclusão em lote. Em particular, cada linha GridView incluirá uma caixa de seleção e, em vez de atualizar todos os botões de tipo, teremos botões Excluir Linhas Selecionadas.
Programação feliz!
Sobre o autor
Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.
Agradecimentos Especiais
Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Teresa Murphy e David Suru. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.