Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. 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, construímos um GridView onde 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 que todas as atualizações sejam revertidas.
Introdução
No tutorial anterior , vimos como estender a camada de acesso a dados para adicionar suporte para 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ão tratadas 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 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 onde 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 GridView e atualizam o banco de dados.
Figura 1: Cada linha no GridView é editável (Clique para visualizar 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, pois 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 Visão geral da inserção, atualização e exclusão de 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 vinculado à sua fonte de dados, ele verifica cada linha para ver se o índice da linha é igual ao valor de EditIndex. Em caso afirmativo, os campos da linha são renderizados usando suas interfaces de edição. Para BoundFields, a interface de edição é uma TextBox cuja propriedade Text recebe o valor do campo de dados especificado pela propriedade DataField do BoundField. Para TemplateFields, o EditItemTemplate é usado no lugar do ItemTemplate.
Lembre-se de que o fluxo de trabalho de edição começa quando um usuário clica no botão Editar de uma linha. Isso causa um postback, define a propriedade do EditIndex GridView como o índice da linha clicada e vincula novamente os dados à grelha. Quando o botão Cancelar de uma linha é clicado, no postback o EditIndex é definido para um valor de -1 antes de reassociar os dados à grelha. Como as linhas de GridView começam a indexar em zero, a configuração 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 fazer com que cada linha seja renderizada com a 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 dos TemplateFields EditItemTemplate s para seus ItemTemplate s.
Etapa 1: Exibindo informações do produto
Antes de nos preocuparmos em criar um GridView onde 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 Toolbox para o Designer. Defina o GridView ID como ProductsGrid e, a partir da sua tag inteligente, escolha vinculá-lo a um novo ObjectDataSource chamado ProductsDataSource. Configure o ObjectDataSource para recuperar seus dados do ProductsBLL método s GetProducts da classe.
Figura 2: Configurar o ObjectDataSource para usar a classe (ProductsBLL imagem em tamanho real)
Figura 3: Recuperar os dados do produto usando o método (GetProducts imagem em tamanho real)
Como o GridView, os recursos de modificação do ObjectDataSource são projetados para funcionar linha a 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 de ObjectDataSource como (Nenhum). Clique em Concluir para finalizar o assistente.
Figura 4: Defina as listas de Drop-Down nas guias UPDATE, INSERT e DELETE como (Nenhuma) (Clique para visualizar a imagem em tamanho real)
Depois de concluir o assistente Configurar Fonte de Dados, a marcação declarativa de ObjectDataSource deve ter a seguinte aparência:
<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, permita que o usuário visualize e edite o nome, a categoria, o preço e o status descontinuado do produto. Remova todos, exceto os ProductNamecampos , CategoryName, UnitPrice, e Discontinued renomeie as HeaderText propriedades dos três primeiros campos para Produto, Categoria e Preço, respectivamente. Por fim, marque as caixas de seleção Ativar Paginação e Ativar Ordenação no smart tag do GridView.
Neste ponto, o GridView tem três BoundFields (ProductName, CategoryNamee 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 o .ItemTemplate
Observação
Exploramos a criação e personalização de TemplateFields no tutorial Customizing the Data Modification Interface . Percorreremos as etapas de conversão de BoundFields e CheckBoxFields em TemplateFields e de definição das suas interfaces de edição utilizando os seus ItemTemplate, mas, caso fique preso ou precise de uma atualização, não hesite em consultar este tutorial anterior.
Na etiqueta inteligente do 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 os BoundFields e CheckBoxField existentes em TemplateField
Agora que cada campo é um TemplateField, estamos prontos para mover a interface de edição do EditItemTemplate s para o ItemTemplate s.
Etapa 2: Criando as interfaces de ProductName, UnitPrice, e Discontinued edição
A criação das interfaces de edição ProductName, UnitPrice e Discontinued é o tópico desta etapa e é bastante simples, pois cada interface já está definida no TemplateField do EditItemTemplate. A criação da CategoryName interface de edição é um pouco mais envolvida, pois precisamos criar uma DropDownList das categorias aplicáveis. Esta CategoryName interface de edição é abordada no Passo 3.
Vamos começar com o ProductName TemplateField. Clique no link Editar Modelos no rótulo inteligente do GridView e navegue até o ProductName TemplateField EditItemTemplate. Selecione a caixa de texto, copie-a para a área de transferência e, em seguida, cole-a no campo de modelo ProductNameItemTemplate. 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 o nome de cada produto. Defina a ControlToValidate propriedade como ProductName, a ErrorMessage propriedade para 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 um TextBox e um RequiredFieldValidator (Clique para visualizar a imagem em tamanho real)
Para a interface de edição UnitPrice, comece copiando o TextBox do EditItemTemplate para o ItemTemplate. Em seguida, coloque um $ na frente do TextBox e defina sua ID propriedade como UnitPrice e sua Columns propriedade como 8 .
Adicione também um CompareValidator ao UnitPrice s ItemTemplate para garantir que o valor inserido pelo usuário seja um valor de moeda válido maior ou igual a $0,00. Defina a propriedade ControlToValidate do validador como UnitPrice e a propriedade ErrorMessage como Deve introduzir um valor de moeda válido. Por favor, omita quaisquer 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 visualizar a imagem em tamanho real)
Para o Discontinued TemplateField, você pode usar a CheckBox já definida no ItemTemplate. Basta definir o seu ID como Descontinuado e a sua propriedade Enabled como true.
Etapa 3: Criando a interface deCategoryNameedição
A interface de edição no CategoryName TemplateField s EditItemTemplate contém um TextBox que exibe o CategoryName valor do campo de dados. Precisamos substituir isso por um DropDownList que lista as categorias possíveis.
Observação
O tutorial Customizing the Data Modification Interface contém uma discussão mais completa e completa sobre a personalização de um modelo para incluir um DropDownList em vez de um TextBox. Embora as etapas aqui estejam completas, elas são apresentadas de forma sucinta. 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 CategoryName TemplateField s ItemTemplate, definindo-o 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, o que resultará em uma instância ObjectDataSource criada para cada linha da GridView. Em vez disso, vamos criar o ObjectDataSource fora dos TemplateFields do GridView. Termine a edição do modelo e arraste um ObjectDataSource da caixa de ferramentas para o Designer abaixo do ProductsDataSource ObjectDataSource. Nomeie o novo ObjectDataSource CategoriesDataSource e configure-o para usar o método s CategoriesBLL da GetCategories classe.
Figura 8: Configurar o ObjectDataSource para usar a classe (CategoriesBLL imagem em tamanho real)
Figura 9: Recuperar os dados da categoria usando o método (GetCategories imagem em tamanho real)
Como este ObjectDataSource é usado apenas para recuperar dados, defina as listas suspensas nas guias Atualizar e Eliminar como (Nenhum). Clique em Concluir para finalizar o assistente.
Figura 10: Defina as listas de Drop-Down nas guias UPDATE e DELETE como (Nenhum) (Clique para visualizar a imagem em tamanho real)
Depois de concluir o assistente, a marcação declarativa CategoriesDataSource deve ter a seguinte aparência:
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Com o CategoriesDataSource criado e configurado, volte aos CategoryName TemplateFields ItemTemplate e, na marca inteligente do DropDownList, clique no link Escolher Fonte de Dados. No assistente de Configuração da Fonte de Dados, selecione a CategoriesDataSource opção da primeira lista suspensa e escolha usar CategoryName para a exibição e CategoryID para o valor.
Figura 11: Vincular o DropDownList ao (CategoriesDataSource 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 vinculado à linha GridView. Para conseguir isso, precisamos definir o Categories DropDownList s SelectedValue para o valor do CategoryID produto. Clique no link Edit DataBindings da etiqueta inteligente DropDownList e associe a SelectedValue propriedade com o CategoryID campo de dados, como mostra a Figura 12.
Figura 12: Vincular 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 databinding on 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 DropDownList s AppendDataBoundItems e true adicione um novo item à DropDownList, omitindo a Value propriedade da sintaxe declarativa. Ou seja, certifique-se de que a Categories sintaxe declarativa de DropDownList tenha a seguinte aparência:
<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 explicitamente definido como uma cadeia de caracteres vazia. Consulte novamente 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 potencial problema de desempenho e escalabilidade aqui que vale a pena mencionar. Como cada linha tem um DropDownList que usa o CategoriesDataSource para a sua fonte de dados, o método CategoriesBLL da classe s GetCategories será chamado n vezes por visita à página, onde n é o número de linhas no GridView. Essas n chamadas para GetCategories produzem n consultas na base 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 um prazo de validade baseado em tempo muito curto.
Etapa 4: Concluindo a interface de edição
Fizemos uma série de alterações nos modelos do GridView sem pausar para ver nosso progresso. Reserve um momento para ver o nosso progresso através 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 visualizar a imagem em tamanho real)
Existem alguns pequenos problemas de formatação que devemos cuidar neste momento. Primeiro, observe que o UnitPrice valor contém quatro casas decimais. Para corrigir isso, retorne ao UnitPrice TemplateField s ItemTemplate e, no marcador inteligente do TextBox, clique no link Edit DataBindings. Em seguida, especifique que a propriedade deve ser formatada Text 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 coluna Discontinued (em vez de a alinhar à esquerda). Clique em Editar colunas da tag inteligente do GridView e selecione o Discontinued TemplateField na lista de campos no canto inferior esquerdo. Analise detalhadamente ItemStyle e defina a propriedade HorizontalAlign como Centralizar, tal como mostrado na Figura 15.
Centralizar a caixa de seleção desativada
Figura 15: Centralizar o Discontinued CheckBox
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 Web Button 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 dos controles Text como Update Products .
Como a interface de edição do GridView é definida nos seus TemplateFields ItemTemplate, os EditItemTemplate são supérfluos e podem ser eliminados.
Depois de fazer as alterações de formatação mencionadas acima, adicionar os controles Button e remover os EditItemTemplate desnecessários, a sintaxe declarativa da página deve ter a seguinte aparência:
<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 visualizada através de um navegador depois que os controles da Web Button foram adicionados e as alterações de formatação feitas.
Figura 16: A página agora inclui dois botões de atualização de produtos (Clique para visualizar a imagem em tamanho real)
Etapa 5: Atualizando os produtos
Quando um usuário visita esta página, ele faz suas modificações e, em seguida, clica 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, passar isso para um método BLL que passará essa ProductsDataTable instância para o método DAL s UpdateWithTransaction . O UpdateWithTransaction método, que criamos no tutorial anterior, garante que o lote de alterações será atualizado como uma operação atômica.
Crie um método nomeado 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);
}
Este método começa por obter todos os produtos de volta em um ProductsDataTable através de uma chamada para o método GetProducts da BLL. Em seguida, enumera a coleção ProductGridRows. A Rows coleção contém uma GridViewRow instância para cada linha exibida no GridView. Como estamos a mostrar no máximo dez linhas por página, a coleção Rows do GridView não terá mais de dez itens.
Para cada linha, o ProductID é retirado da coleção DataKeys e o apropriado ProductsRow é selecionado a partir do ProductsDataTable. Os quatro controlos de entrada TemplateField são referenciados por programação, e os seus valores são atribuídos às propriedades da instância ProductsRow. Depois de cada valor de linha do GridView ter sido usado para atualizar o ProductsDataTable, este é 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 que corresponde a uma linha no GridView, independentemente de as informações do produto terem sido alteradas. Embora essas atualizações ocultas geralmente não sejam um problema de desempenho, elas podem levar a registros supérfluos se você estiver auditando alterações na tabela do banco de dados. De volta ao tutorial Executando atualizações em lote, 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. Sinta-se à vontade para usar as técnicas de Executando atualizações em lote para atualizar o código neste tutorial, se desejar.
Observação
Ao vincular a fonte de dados ao GridView por meio de sua marca inteligente, o Visual Studio atribui automaticamente o(s) valor(es) da chave primária da fonte de dados à propriedade GridView DataKeyNames . Se você não associou o ObjectDataSource ao GridView através da tag inteligente do GridView, conforme descrito na Etapa 1, vai precisar definir manualmente a propriedade DataKeyNames do GridView como ProductID para acessar o valor ProductID de cada linha através da coleção DataKeys.
O código usado em BatchUpdate é semelhante ao usado nos métodos da UpdateProduct BLL, sendo a principal diferença que nos métodos UpdateProduct apenas uma única instância ProductRow é recuperada da arquitetura. O código que atribui as propriedades do ProductRow é o mesmo tanto entre os métodos UpdateProducts quanto ao código dentro do loop foreach em BatchUpdate, bem como o padrão geral.
Para concluir este tutorial, precisamos invocar o método BatchUpdate quando um dos botões Atualizar Produtos é 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, é feita uma chamada para BatchUpdate. Em seguida, o ClientScript property é usado para injetar JavaScript que exibirá uma caixa de mensagem que lê Os produtos foram atualizados.
Reserve um minuto para testar este código. Visite BatchUpdate.aspx através de 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ê 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, a partir de BatchUpdate.aspx, edite uma série de registros UnitPrice , certificando-se de definir um dos valores do produto para o valor proibido ( 1234,56 ). Isso deve resultar em um erro ao clicar em Atualizar Produtos, enquanto as outras alterações dessa operação em lote são revertidas para seus valores originais.
Um método alternativoBatchUpdate
O BatchUpdate método que acabamos de examinar recupera todos os produtos do método BLL s GetProducts e, em seguida, atualiza apenas os registros que aparecem no GridView. Essa abordagem é ideal se o GridView não usar paginação, mas se usar, pode 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 não é o ideal.
Para essas situações, considere usar o método seguinte BatchUpdateAlternate.
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 do GridView Rows e, para cada linha, obtém as informações específicas do produto usando o método do BLL GetProductByProductID(productID). A instância obtida ProductsRow tem as 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) do DataTable.
Após o foreach loop concluir, products contém uma instância de ProductsRow para cada linha no GridView. Como cada uma das ProductsRow instâncias foi adicionada ao products (em vez de atualizada), se as passarmos sem tratamento ao método UpdateWithTransaction, o ProductsTableAdapter tentará inserir cada um dos registos 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 chamado UpdateProductsWithTransaction.
UpdateProductsWithTransaction, mostrado abaixo, define o RowState de cada uma das ProductsRow instâncias no ProductsDataTable para Modified e, em seguida, passa o ProductsDataTable para o método UpdateWithTransaction da 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 a criação de interfaces totalmente editáveis. Como vimos neste tutorial, tais interfaces são possíveis, mas exigem um pouco de trabalho. Para criar um GridView onde cada linha é editável, precisamos converter os campos s de GridView em TemplateFields e definir a interface de edição dentro do ItemTemplate s. Além disso, os controlos Web denominados "Update All -type Button" devem ser adicionados à página, separados do GridView. Esses manipuladores de eventos Buttons Click precisam enumerar a coleção Rows do GridView, 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 do GridView incluirá uma caixa de seleção e, em vez dos botões de Atualizar Todos -type, teremos botões para Eliminar Linhas Selecionadas.
Feliz Programação!
Sobre o Autor
Scott Mitchell, autor de sete livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Ele pode ser contatado em mitchell@4GuysFromRolla.com.
Um agradecimento especial 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 rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.