Atualização em lote (VB)
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 que 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 seja tratada como uma operação atômica, o que garante que todas as modificações falhem ou todas sejam 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 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, pois usa um GridView e a atualização em lote é executada dentro do escopo de uma transação. Depois de concluir este tutorial, recomendo que você retorne ao tutorial anterior e atualize-o para usar a funcionalidade relacionada à transação de banco de dados adicionada no tutorial anterior.
Examinando as etapas para tornar todas as linhas do GridView editáveis
Conforme discutido no tutorial Uma 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. À medida que 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, 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 recebe o 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 começa quando um usuário clica no botão Editar de uma linha. Isso causa um postback, define a propriedade GridView EditIndex
como o índice da linha clicada e associa novamente os dados à grade. Quando o 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 EditIndex
de -1
como 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 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 converteremos seus BoundFields e CheckBoxField em TemplateFields. Nas Etapas 2 e 3, moveremos as interfaces de edição do TemplateFields EditItemTemplate
s para o s ItemTemplate
.
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 BatchUpdate.aspx
página na BatchData
pasta e arraste um GridView da Caixa de Ferramentas para o Designer. Defina o GridView ID
como ProductsGrid
e, em sua marca inteligente, opte por associá-lo a um novo ObjectDataSource chamado ProductsDataSource
. Configure o ObjectDataSource para recuperar seus dados do ProductsBLL
método da GetProducts
classe.
Figura 2: Configurar o ObjectDataSource para usar a classe (clique para exibir a ProductsBLL
imagem em tamanho completo)
Figura 3: Recuperar os dados do produto usando o método (clique para exibir a GetProducts
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: Defina as listas suspensas 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>
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 o status descontinuado do produto. Remova todos os campos, exceto , ProductName
, UnitPrice
CategoryName
, 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 Habilitar Paginação e Habilitar Classificação na marca inteligente do 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 EditItemTemplate
para seu ItemTemplate
.
Observação
Exploramos a criação e personalização de TemplateFields no tutorial Personalizando a interface de modificação de dados. Percorreremos 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 uma atualização, não hesite em consultar este tutorial anterior.
Na marca 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 TemplateFields
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 asProductName
interfaces eUnitPrice
Discontinued
editando
A criação das ProductName
interfaces , UnitPrice
e Discontinued
de edição são o tópico desta etapa e são bastante simples, pois cada interface já está definida no TemplateField EditItemTemplate
. A criação da CategoryName
interface de edição é um pouco mais complicada, 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 da marca inteligente do GridView e faça uma busca detalhada no ProductName
TemplateField EditItemTemplate
. Selecione o TextBox, copie-o para a área de transferência e cole-o no ProductName
TemplateField ItemTemplate
. Altere a propriedade do TextBox 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 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 um TextBox e um RequiredFieldValidator (clique para exibir a imagem em tamanho real)
Para a UnitPrice
interface de edição, comece copiando o TextBox do EditItemTemplate
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 US$ 0,00. Defina a propriedade do ControlToValidate
validador como UnitPrice, sua ErrorMessage
propriedade como Você deve inserir 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 exibir a imagem em tamanho real)
Para o Discontinued
TemplateField, você pode usar o CheckBox já definido no ItemTemplate
. Basta definir sua ID
propriedade como Descontinuado e sua Enabled
propriedade como True
.
Etapa 3: Criando aCategoryName
interface de edição
A interface de edição no CategoryName
TemplateField contém EditItemTemplate
um TextBox que exibe o valor do CategoryName
campo de 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 completas, elas são apresentadas de forma concisa. Para obter uma visão mais detalhada da criação e configuração das 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
definindo seu ID
Categories
como . Neste ponto, normalmente definiríamos a fonte de dados DropDownLists por meio de sua marca inteligente, criando um novo ObjectDataSource. No entanto, isso adicionará o ObjectDataSource dentro do , o ItemTemplate
que resultará em uma instância ObjectDataSource criada para cada linha GridView. Em vez disso, vamos criar o ObjectDataSource fora do GridView TemplateFields. Finalize 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 CategoriesBLL
método da GetCategories
classe.
Figura 8: Configurar o ObjectDataSource para usar a classe (clique para exibir a CategoriesBLL
imagem em tamanho completo)
Figura 9: Recuperar os dados da categoria usando o método (clique para exibir a GetCategories
imagem em tamanho real)
Como esse 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 as listas suspensas 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 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 e ItemTemplate
, na marca inteligente DropDownList , clique no link Escolher Fonte de Dados . No assistente de Configuração da Fonte de Dados, selecione a CategoriesDataSource
opção na primeira lista suspensa e escolha ter CategoryName
usado para a exibição e CategoryID
como o valor.
Figura 11: Associar o DropDownList ao (Clique para exibir a CategoriesDataSource
imagem em tamanho completo)
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
como o valor do CategoryID
produto. Clique no link Edit DataBindings da marca inteligente DropDownList e associe a SelectedValue
propriedade ao campo de dados, CategoryID
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 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 True
DropDownList 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 -- <asp:ListItem Value="">
Select One -- tem seu Value
atributo explicitamente definido como uma string vazia. Consulte o tutorial Personalizando a Interface de Modificação de Dados para obter 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 CategoriesBLL
método da classe será GetCategories
chamado n vezes por visita de página, em que n é o número de linhas no GridView. Essas n chamadas resultam GetCategories
em n consultas ao 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 exibir 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 do GridView é editável (clique para exibir a imagem em tamanho real)
Existem alguns pequenos problemas de formatação que devemos resolver neste momento. Primeiro, observe que o UnitPrice
valor contém quatro casas decimais. Para corrigir isso, retorne ao UnitPrice
TemplateField e ItemTemplate
, na marca inteligente do TextBox, clique no link Editar 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 Discontinued
coluna (em vez de alinhá-la à esquerda). Clique em Editar Colunas da marca inteligente do GridView e selecione o Discontinued
TemplateField na lista de campos no canto inferior esquerdo. Faça uma busca detalhada ItemStyle
e defina a propriedade como Center, HorizontalAlign
como mostra a Figura 15.
Figura 15: Centralizar a Discontinued
caixa de seleção
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 de botão que, quando clicados, atualizarão as alterações do 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
como Atualizar produtos.
Como a interface de edição do GridView é definida em seus TemplateFields ItemTemplate
s, os s são supérfluos EditItemTemplate
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 depois que os controles Web de botão foram adicionados e as alterações de formatação feitas.
Figura 16: A página agora inclui dois botões Atualizar produtos (clique para exibir a imagem em tamanho real)
Etapa 5: Atualizando os produtos
Quando um usuário visita esta página, ele faz suas modificações e 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, passá-los para um método BLL que passará essa ProductsDataTable
instância para o método DAL 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 nomeado BatchUpdate
em BatchUpdate.aspx.vb
e adicione o seguinte código:
Private Sub BatchUpdate()
' Enumerate the GridView's Rows collection and create a ProductRow
Dim productsAPI As New ProductsBLL()
Dim products As Northwind.ProductsDataTable = productsAPI.GetProducts()
For Each gvRow As GridViewRow In ProductsGrid.Rows
' Find the ProductsRow instance in products that maps to gvRow
Dim productID As Integer = _
Convert.ToInt32(ProductsGrid.DataKeys(gvRow.RowIndex).Value)
Dim product As Northwind.ProductsRow = products.FindByProductID(productID)
If product IsNot Nothing Then
' Programmatically access the form field elements in the
' current GridViewRow
Dim productName As TextBox = _
CType(gvRow.FindControl("ProductName"), TextBox)
Dim categories As DropDownList = _
CType(gvRow.FindControl("Categories"), DropDownList)
Dim unitPrice As TextBox = _
CType(gvRow.FindControl("UnitPrice"), TextBox)
Dim discontinued As CheckBox = _
CType(gvRow.FindControl("Discontinued"), CheckBox)
' Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim()
If categories.SelectedIndex = 0 Then
product.SetCategoryIDNull()
Else
product.CategoryID = Convert.ToInt32(categories.SelectedValue)
End If
If unitPrice.Text.Trim().Length = 0 Then
product.SetUnitPriceNull()
Else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text)
End If
product.Discontinued = discontinued.Checked
End If
Next
' Now have the BLL update the products data using a transaction
productsAPI.UpdateWithTransaction(products)
End Sub
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 ProductGrid
coleção do Rows
GridView. 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 do Rows
GridView não terá mais de dez itens.
Para cada linha, o ProductID
é obtido 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 propriedades da ProductsRow
instância. Depois que os valores de cada linha GridView forem usados para atualizar o ProductsDataTable
, ele será passado para o método da UpdateWithTransaction
BLL que, como vimos no tutorial anterior, simplesmente chama o método da DAL 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 terem sido 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 do 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 um 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 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 do DataKeyNames
GridView. Se você não associou o ObjectDataSource ao GridView por meio da marca inteligente do GridView, conforme descrito na Etapa 1, precisará definir manualmente a propriedade do GridView DataKeyNames
como ProductID para acessar o valor de ProductID
cada linha por meio da DataKeys
coleção.
O código usado em BatchUpdate
é semelhante ao usado nos métodos da UpdateProduct
BLL, a principal 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 For Each
loop em BatchUpdate
, assim como o padrão geral.
Para concluir este tutorial, precisamos ter o BatchUpdate
método invocado 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(Me.GetType(), "message", _
"alert('The products have been updated.');", True)
Primeiro, uma chamada é feita para BatchUpdate
. Em seguida, a ClientScript
propriedade é usada para injetar JavaScript que exibirá uma caixa de mensagem que diz Os produtos foram atualizados.
Reserve um minuto para testar este código. Visite BatchUpdate.aspx
por meio 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ê deverá ver uma caixa de mensagem que diz 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 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, 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 é menos do que o ideal.
Para esses tipos de situações, considere usar o seguinte BatchUpdateAlternate
método:
Private Sub BatchUpdateAlternate()
' Enumerate the GridView's Rows collection and create a ProductRow
Dim productsAPI As New ProductsBLL()
Dim products As New Northwind.ProductsDataTable()
For Each gvRow As GridViewRow In ProductsGrid.Rows
' Create a new ProductRow instance
Dim productID As Integer = _
Convert.ToInt32(ProductsGrid.DataKeys(gvRow.RowIndex).Value)
Dim currentProductDataTable As Northwind.ProductsDataTable = _
productsAPI.GetProductByProductID(productID)
If currentProductDataTable.Rows.Count > 0 Then
Dim product As Northwind.ProductsRow = currentProductDataTable(0)
Dim productName As TextBox = _
CType(gvRow.FindControl("ProductName"), TextBox)
Dim categories As DropDownList = _
CType(gvRow.FindControl("Categories"), DropDownList)
Dim unitPrice As TextBox = _
CType(gvRow.FindControl("UnitPrice"), TextBox)
Dim discontinued As CheckBox = _
CType(gvRow.FindControl("Discontinued"), CheckBox)
' Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim()
If categories.SelectedIndex = 0 Then
product.SetCategoryIDNull()
Else
product.CategoryID = Convert.ToInt32(categories.SelectedValue)
End If
If unitPrice.Text.Trim().Length = 0 Then
product.SetUnitPriceNull()
Else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text)
End If
product.Discontinued = discontinued.Checked
' Import the ProductRow into the products DataTable
products.ImportRow(product)
End If
Next
' Now have the BLL update the products data using a transaction
productsAPI.UpdateProductsWithTransaction(products)
End Sub
BatchMethodAlternate
começa criando um novo vazio ProductsDataTable
chamado products
. Em seguida, ele percorre a coleção do Rows
GridView e, para cada linha, obtém as informações específicas do produto usando o método da GetProductByProductID(productID)
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 método por meio do ProductsDataTable
products
DataTable ImportRow(DataRow)
método .
Após a conclusão do For Each
loop, products
contém uma ProductsRow
instância para cada linha no GridView. Uma vez que cada uma das ProductsRow
instâncias foi adicionada ao products
(em vez de atualizado), se passarmos cegamente para o UpdateWithTransaction
método, ele 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 chamado UpdateProductsWithTransaction
. UpdateProductsWithTransaction
, mostrado abaixo, define o RowState
de cada uma das ProductsRow
instâncias no ProductsDataTable
to Modified
e, em seguida, passa o ProductsDataTable
para o método do UpdateWithTransaction
DAL.
Public Function UpdateProductsWithTransaction _
(ByVal products As Northwind.ProductsDataTable) As Integer
' Mark each product as Modified
products.AcceptChanges()
For Each product As Northwind.ProductsRow In products
product.SetModified()
Next
' Update the data via a transaction
Return UpdateWithTransaction(products)
End Function
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, 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 do ItemTemplate
s. Além disso, os controles Web de botão do tipo Atualizar todos devem ser adicionados à página, separados do GridView. Esses manipuladores de eventos 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 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 de botões do tipo Atualizar Tudo, teremos botões Excluir Linhas Selecionadas.
Boa programação!
Sobre o autor
Scott Mitchell, autor de sete livros ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Web da Microsoft desde 1998. Scott trabalha como consultor, instrutor e escritor independente. 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 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? Em caso afirmativo, envie-me uma mensagem para mitchell@4GuysFromRolla.com.