Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
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 em 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 serão bem-sucedidas. 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 lotes.
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 de botões Editar, Atualizar e Cancelar. Em vez disso, há dois botões Atualizar Produtos na página que, quando clicados, enumeram as linhas do 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 Atualizações em Lote , criamos uma interface de edição em lote usando o controle DataList. Este tutorial difere do anterior em que se 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 Inserir, Atualizar e Excluir Dados , o GridView oferece suporte interno para editar seus dados subjacentes por linha. Internamente, o GridView observa qual linha é editável por meio de sua EditIndex propriedade. Como o GridView está sendo associado à fonte de dados, ele verifica cada linha para ver se o índice da linha é igual ao valor de EditIndex. Nesse caso, os campos dessa linha 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 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 EditIndex para o índice da linha clicada e vincula novamente os dados à grade. Quando o botão Cancelar de uma linha é clicado, no postback, EditIndex é definido como o valor de -1 antes de vincular novamente os dados à grade. Como as linhas do GridView começam a indexar em zero, definir EditIndex para -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 que cada linha seja exibida 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 converteremos seus BoundFields e CheckBoxField em TemplateFields. Nas Etapas 2 e 3, moveremos as interfaces de edição das TemplateFields EditItemTemplate para ItemTemplate s.
Etapa 1: Exibindo informações do produto
Antes de nos preocuparmos com a criação de um GridView em que as linhas são editáveis, vamos começar simplesmente exibindo as informações do produto. Abra a página BatchUpdate.aspx na pasta BatchData e arraste um GridView da Caixa de Ferramentas para o Designer. Defina o atributo de ID do GridView para ProductsGrid e, de sua smart tag, escolha associá-lo a um novo ObjectDataSource chamado ProductsDataSource. Configure o ObjectDataSource para recuperar dados do método ProductsBLL da classe 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 (Nenhuma). Clique em "Finalizar" para completar o assistente.
Figura 4: Definir as listas de Drop-Down 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 deve ser semelhante à seguinte:
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
Ao concluir o assistente Configurar Fonte de Dados, o Visual Studio também cria 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 o status descontinuado do produto. Remova todos os campos, exceto os ProductName, CategoryName, UnitPrice e Discontinued e renomeie as propriedades HeaderText dos três primeiros campos para Produto, Categoria e Preço, respectivamente. Por fim, marque as caixas de seleção Habilitar Paginação e Habilitar Classificação na marca inteligente do GridView.
Neste ponto, o GridView tem três BoundFields (ProductNamee CategoryName) e UnitPriceum CheckBoxField (Discontinued). Precisamos converter esses quatro campos em TemplateFields e, em seguida, mover a interface de edição do EditItemTemplate TemplateField 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 definir suas interfaces de edição em suas ItemTemplate s. Mas, se você ficar preso ou precisar de uma revisão, não hesite em consultar este tutorial anterior.
Na tag inteligente do GridView, clique no link Editar Colunas para abrir a caixa de diálogo de campos. Em seguida, selecione cada campo e clique no link Converter este campo em um link TemplateField.
Figura 5: Converter os BoundFields existentes e CheckBoxField 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 as interfaces de ProductName, UnitPrice, e Discontinued edição
Criar as interfaces de edição ProductName, UnitPrice e Discontinued é o tópico desta etapa e é bastante simples, pois cada interface já está definida nos TemplateFields EditItemTemplate. A criação da CategoryName interface de edição é um pouco mais envolvida, pois precisamos criar um DropDownList das categorias aplicáveis. Essa CategoryName interface de edição é abordada na Etapa 3.
Vamos começar com o ProductName TemplateField. Clique no link Editar Modelos na tag inteligente do GridView e aprofunde-se no ProductName TemplateField EditItemTemplate. Selecione a Caixa de Texto, copie-a para a área de transferência e cole-a no ProductName TemplateField s ItemTemplate. Altere a propriedade de ID do TextBox 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 para Você deve fornecer o nome do produto. e a propriedade Text para *. Depois de fazer essas adições à tela ItemTemplate, ela deve se parecer com a Figura 6.
Figura 6: O ProductName TemplateField agora inclui uma Caixa de Texto e um RequiredFieldValidator (Clique para exibir a imagem em tamanho real)
Para a UnitPrice interface de edição, comece copiando o TextBox do EditItemTemplate para o ItemTemplate. Em seguida, coloque um $ à frente do 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 ControlToValidate do validador como UnitPrice e a propriedade ErrorMessage como 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 para 0 .
Figura 7: Adicionar um CompareValidator para garantir que o preço inserido seja um valor de moeda não negativo (clique para exibir a imagem em tamanho real)
Para o Discontinued TemplateField, você pode usar a Caixa de Seleção já definida na ItemTemplate. Basta definir como ID Descontinuado e sua Enabled propriedade como true.
Etapa 3: Criando aCategoryNameinterface 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 substituí-lo 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 de forma resumida. Para obter uma análise 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 CategoryName TemplateField ItemTemplate e defina seu ID como Categories. 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á o ObjectDataSource dentro do ItemTemplate, que resultará na criação de uma instância de ObjectDataSource para cada linha do GridView. Em vez disso, vamos criar o ObjectDataSource fora dos TemplateFields do GridView. Encerre a edição do modelo. Em seguida, arraste um ObjectDataSource da caixa de ferramentas para o Designer, posicionando-o abaixo do ProductsDataSource ObjectDataSource. Nomeie o novo ObjectDataSource CategoriesDataSource e configure-o para usar o CategoriesBLL método da GetCategories classe.
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 "Finalizar" para completar o assistente.
Figura 10: Definir as listas de Drop-Down 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 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 de Configuração da Fonte de Dados, selecione a opção CategoriesDataSource na primeira lista suspensa e escolha usar CategoryName para a exibição e CategoryID como o valor.
Figura 11: Associar o DropDownList à 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 realizar isso, precisamos definir os Categories DropDownLists SelectedValue para o valor do produto CategoryID. 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 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 esses produtos que têm um NULL valor de banco de dados para CategoryID. Para corrigir isso, defina a propriedade do DropDownList para AppendDataBoundItems, aplique a propriedade true e adicione um novo item ao DropDownList, omitindo a propriedade Value 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=""> atributo -- 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 uma discussão mais completa 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 método CategoriesBLL da classe 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 resultam em n consultas para o banco de dados. Esse impacto no banco de dados pode ser reduzido ao armazenar em cache as categorias retornadas, seja por meio de um cache por solicitação ou através da Camada de Caching, utilizando uma dependência de cache SQL ou uma expiração baseada em um tempo muito curto.
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 sua ItemTemplate, que contém a interface de edição da célula.
Figura 13: Cada linha GridView é editável (clique para exibir a imagem em tamanho real)
Há algumas pequenas questões de formatação que devemos cuidar neste momento. Primeiro, observe que o UnitPrice valor contém quatro pontos decimais. Para corrigir isso, retorne aos UnitPrice TemplateFields ItemTemplate e, na tag inteligente dos TextBoxes, 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 o Discontinued TemplateField na lista de campos no canto inferior esquerdo. Aprofunde-se em ItemStyle e defina a propriedade HorizontalAlign como Centro, conforme ilustrado na Figura 15.
Figura 15: Centralizar a Discontinued Caixa de Seleção
Em seguida, adicione um controle ValidationSummary à página, defina sua propriedade ShowMessageBox como true e sua propriedade ShowSummary como false. Adicione também os controles de botão da Web que, quando clicados, atualizarão as alterações feitas pelo usuário. Especificamente, adicione dois controles Web de botão, um acima do GridView e outro abaixo dele, definindo ambas as propriedades de controle Text para Atualizar Produtos.
Como a interface de edição do GridView é definida em seus TemplateFields ItemTemplate , 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 de botão e remover os EditItemTemplate desnecessários, 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 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á-lo para um método BLL que, em seguida, passará essa ProductsDataTable instância para o método da UpdateWithTransaction DAL. 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 nomeado BatchUpdateBatchUpdate.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 da GetProducts BLL. Em seguida, ele enumera a coleção ProductGrid GridViewRows. 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 é extraído da coleção DataKeys e o ProductsRow apropriado é selecionado a partir de ProductsDataTable. Os quatro controles de entrada TemplateField são referenciados através de programação e seus valores atribuídos às propriedades da instância ProductsRow. Depois que os valores de cada linha do GridView tiverem sido usados para atualizar o ProductsDataTable, ele será passado para o método UpdateWithTransaction da BLL, que, como vimos no tutorial anterior, simplesmente chama o método UpdateWithTransaction da DAL.
O algoritmo de atualização em lote usado para este tutorial atualiza cada linha na ProductsDataTable qual 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 Atualizações em Lote , exploramos uma interface de atualização em lote com o DataList e adicionamos código que só atualizaria os registros que foram realmente modificados pelo usuário. Fique à vontade para usar as técnicas de Execução de Atualizações em 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 o ObjectDataSource ao GridView usando o smart tag do GridView, conforme descrito na Etapa 1, será necessário definir manualmente a propriedade DataKeyNames do GridView como ProductID para acessar o valor de ProductID de cada linha através da coleção DataKeys.
O código usado BatchUpdate é semelhante ao usado nos métodos da BLL, sendo que a principal diferença é que, nos UpdateProduct métodos, apenas uma única UpdateProduct instância é recuperada da arquitetura. O código que atribui as propriedades do ProductRow é o mesmo entre os métodos UpdateProducts e o código dentro do loop foreach em BatchUpdate, mantendo o padrão geral.
Para concluir este tutorial, precisamos ter o BatchUpdate método invocado quando qualquer um dos botões atualizar produtos é clicado. Crie manipuladores de eventos para os Click eventos desses dois controles de botão 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.
BatchUpdate.aspxEm seguida, 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 revertidas para seus valores originais.
Um método alternativoBatchUpdate
O BatchUpdate método que acabamos de examinar recupera todos os produtos do método 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 ProductsDataTable vazio chamado products. Em seguida, ele percorre a coleção do GridView Rows e, para cada linha, obtém as informações específicas do produto usando o método GetProductByProductID(productID) da BLL. A instância recuperada ProductsRow tem suas propriedades atualizadas da mesma forma que BatchUpdate, mas, depois de atualizar a linha, ela é importada para o products``ProductsDataTable através do método ImportRow(DataRow) da DataTable.
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 foram adicionadas ao products (em vez de atualizadas), se passarmos cegamente o método UpdateWithTransaction, 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 a RowState de cada uma das instâncias ProductsRow em ProductsDataTable para Modified e então passa o ProductsDataTable para o método UpdateWithTransaction do 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);
}
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 seja editável, precisamos converter os campos de GridView em TemplateFields e definir a interface de edição dentro dos ItemTemplate s. Além disso, todos os controles Web do "-type Button" devem ser atualizados e adicionados à página, separados do GridView. Esses manipuladores de eventos dos Buttons Click precisam enumerar a coleção do GridView Rows, armazenar as alterações em um ProductsDataTable, e passar as informações atualizadas para o método apropriado do BLL.
No próximo tutorial, veremos como criar uma interface para exclusão em lote. Em particular, cada linha do GridView incluirá uma caixa de seleção e, em vez de botões "Update All -type", teremos botões "Excluir Linhas Selecionadas".
Divirta-se programando!
Sobre o autor
Scott Mitchell, autor de sete livros 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 alcançado em mitchell@4GuysFromRolla.com.
Agradecimentos Especiais a
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? Se assim for, deixe-me uma linha em mitchell@4GuysFromRolla.com.