Partilhar via


Executando atualizações em lote (VB)

por Scott Mitchell

Descarregar PDF

Saiba como criar uma DataList totalmente editável onde todos os seus itens estão no modo de edição e cujos valores podem ser salvos clicando no botão "Atualizar tudo" na página.

Introdução

No tutorial anterior , examinamos como criar uma DataList no nível do item. Como o GridView editável padrão, cada item na DataList incluía um botão Editar que, quando clicado, tornaria o item editável. Embora essa edição no nível do item funcione bem para dados que só são atualizados ocasionalmente, certos cenários de caso de uso exigem que o usuário edite muitos registros. Se um usuário precisa editar dezenas de registros e é forçado a clicar em Editar, fazer suas alterações e clicar em Atualizar para cada um, a quantidade de cliques pode prejudicar sua produtividade. Em tais situações, uma opção melhor é fornecer uma DataList totalmente editável, onde todos os seus itens estão no modo de edição e cujos valores podem ser editados clicando em um botão Atualizar tudo na página (veja a Figura 1).

Cada item em uma lista de dados totalmente editável pode ser modificado

Figura 1: Cada item em uma lista de dados totalmente editável pode ser modificado (Clique para visualizar a imagem em tamanho real)

Neste tutorial, examinaremos como permitir que os usuários atualizem as informações de endereço dos fornecedores usando uma DataList totalmente editável.

Etapa 1: Criar a interface do usuário editável no DataList s ItemTemplate

No tutorial anterior, onde criamos uma DataList editável padrão em nível de item, usamos dois modelos:

  • ItemTemplate continha a interface de usuário somente leitura (os controles Label Web para exibir o nome e o preço de cada produto).
  • EditItemTemplate continha a interface de utilizador do modo de edição (os dois controles Web do TextBox).

A propriedade DataList s EditItemIndex dita o que DataListItem (se houver) é renderizado usando o EditItemTemplate. Em particular, o DataListItem cujo valor de ItemIndex corresponde à propriedade EditItemIndex do DataList é renderizado usando o EditItemTemplate. Esse modelo funciona bem quando apenas um item pode ser editado de cada vez, mas cai por terra ao criar uma DataList totalmente editável.

Para uma DataList totalmente editável, queremos que todos os DataListItem s sejam renderizados usando a interface editável. A maneira mais simples de fazer isso é definir a interface editável no ItemTemplate. Para modificar as informações de endereço dos fornecedores, a interface editável contém o nome do fornecedor como texto e, em seguida, TextBoxes para os valores de endereço, cidade e país/região.

Comece abrindo a BatchUpdate.aspx página, adicione um controle DataList e defina sua ID propriedade como Suppliers. No balão inteligente do DataList, opte por adicionar um novo controlo ObjectDataSource chamado SuppliersDataSource.

Criar um novo ObjectDataSource chamado SuppliersDataSource

Figura 2: Criar um novo ObjectDataSource nomeado SuppliersDataSource (Clique para visualizar a imagem em tamanho real)

Configure o ObjectDataSource para recuperar dados usando o método SuppliersBLL de GetSuppliers() classe (consulte a Figura 3). Como no tutorial anterior, em vez de atualizar as informações do fornecedor por meio do ObjectDataSource, trabalharemos diretamente com a camada de lógica de negócios. Portanto, defina a lista suspensa como (Nenhum) na guia UPDATE (veja a Figura 4).

Recuperar informações do fornecedor usando o método GetSuppliers()

Figura 3: Recuperar informações do fornecedor usando o método (GetSuppliers() imagem em tamanho real)

Defina a lista de Drop-Down como (Nenhum) na guia ATUALIZAR

Figura 4: Defina a lista de Drop-Down como (Nenhum) na guia UPDATE (Clique para visualizar a imagem em tamanho real)

Depois de concluir o assistente, o Visual Studio gera automaticamente o DataList s ItemTemplate para exibir cada campo de dados retornado pela fonte de dados em um controle Web Label. Precisamos modificar este modelo para que ele forneça a interface de edição. O ItemTemplate pode ser personalizado através do Designer usando a opção Editar Templates do Smart Tag do DataList ou diretamente através da sintaxe declarativa.

Reserve um momento para criar uma interface de edição que exiba o nome do fornecedor como texto, mas inclua TextBoxes para o endereço do fornecedor, cidade e valores de país/região. Depois de fazer essas alterações, a sintaxe declarativa da página deve ser semelhante à seguinte:

<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID"
    DataSourceID="SuppliersDataSource">
    <ItemTemplate>
        <h4><asp:Label ID="CompanyNameLabel" runat="server"
            Text='<%# Eval("CompanyName") %>' /></h4>
        <table border="0">
            <tr>
                <td class="SupplierPropertyLabel">Address:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Address" runat="server"
                        Text='<%# Eval("Address") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">City:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="City" runat="server"
                        Text='<%# Eval("City") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">Country:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Country" runat="server"
                        Text='<%# Eval("Country") %>' />
                </td>
            </tr>
        </table>
        <br />
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>

Observação

Como no tutorial anterior, o DataList neste tutorial deve ter seu estado de exibição habilitado.

No ItemTemplate, estou a usar duas novas classes CSS, SupplierPropertyLabel e SupplierPropertyValue, que foram adicionadas à classe Styles.css e configuradas para usar as mesmas configurações de estilo que as classes CSS ProductPropertyLabel e ProductPropertyValue.

.ProductPropertyLabel, .SupplierPropertyLabel
{
    font-weight: bold;
    text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
    padding-right: 35px;
}

Depois de fazer essas alterações, visite esta página através de um navegador. Como mostra a Figura 5, cada item DataList exibe o nome do fornecedor como texto e usa TextBoxes para exibir o endereço, a cidade e o país/região.

Cada fornecedor na DataList é editável

Figura 5: Cada fornecedor na DataList é editável (Clique para visualizar a imagem em tamanho real)

Etapa 2: Adicionando um botão Atualizar tudo

Embora cada fornecedor na Figura 5 tenha seus campos de endereço, cidade e país/região exibidos em uma TextBox, atualmente não há nenhum botão Update disponível. Em vez de ter um botão Atualizar por item, com DataLists totalmente editáveis, normalmente há um único botão Atualizar Tudo na página que, quando clicado, atualiza todos os registros na DataList. Para este tutorial, vamos adicionar dois botões Atualizar tudo - um na parte superior da página e outro na parte inferior (embora clicar em qualquer um dos botões tenha o mesmo efeito).

Comece adicionando um controle Web Button acima de DataList e defina sua ID propriedade como UpdateAll1. Em seguida, adicione o segundo controle Web Button abaixo de DataList, definindo-o ID como UpdateAll2. Defina as Text propriedades dos dois botões para atualizar tudo. Por fim, crie manipuladores de eventos para ambos os eventos dos botões Click. Em vez de duplicar a lógica de atualização em cada um dos manipuladores de eventos, vamos refatorar essa lógica para um terceiro método, UpdateAllSupplierAddressesfazendo com que os manipuladores de eventos simplesmente invoquem esse terceiro método.

Protected Sub UpdateAll1_Click(sender As Object, e As EventArgs) _
    Handles UpdateAll1.Click
    UpdateAllSupplierAddresses()
End Sub
Protected Sub UpdateAll2_Click(sender As Object, e As EventArgs) _
    Handles UpdateAll2.Click
    UpdateAllSupplierAddresses()
End Sub
Private Sub UpdateAllSupplierAddresses()
    ' TODO: Write code to update _all_ of the supplier addresses in the DataList
End Sub

A Figura 6 mostra a página depois que os botões Update All foram adicionados.

Dois botões de atualização foram adicionados à página

Figura 6: Dois botões de atualização foram adicionados à página (Clique para visualizar a imagem em tamanho real)

Etapa 3: Atualizando todas as informações de endereço dos fornecedores

Com todos os itens de DataList exibindo a interface de edição e com a adição dos botões Atualizar tudo, tudo o que resta é escrever o código para executar a atualização em lote. Especificamente, precisamos percorrer os itens do DataList e chamar o método da classe SuppliersBLLUpdateSupplierAddress para cada um.

A coleção de DataListItem instâncias que compõem o DataList pode ser acessada por meio da propriedade Items do DataList. Com uma referência a um DataListItem, podemos pegar o correspondente SupplierID da DataKeys coleção e referenciar programaticamente os controles da Web TextBox dentro do ItemTemplate como o código a seguir ilustra:

Private Sub UpdateAllSupplierAddresses()
    ' Create an instance of the SuppliersBLL class
    Dim suppliersAPI As New SuppliersBLL()
    ' Iterate through the DataList's items
    For Each item As DataListItem In Suppliers.Items
        ' Get the supplierID from the DataKeys collection
        Dim supplierID As Integer = Convert.ToInt32(Suppliers.DataKeys(item.ItemIndex))
        ' Read in the user-entered values
        Dim address As TextBox = CType(item.FindControl("Address"), TextBox)
        Dim city As TextBox = CType(item.FindControl("City"), TextBox)
        Dim country As TextBox = CType(item.FindControl("Country"), TextBox)
        Dim addressValue As String = Nothing, _
            cityValue As String = Nothing, _
            countryValue As String = Nothing
        If address.Text.Trim().Length > 0 Then
            addressValue = address.Text.Trim()
        End If
        If city.Text.Trim().Length > 0 Then
            cityValue = city.Text.Trim()
        End If
        If country.Text.Trim().Length > 0 Then
            countryValue = country.Text.Trim()
        End If
        ' Call the SuppliersBLL class's UpdateSupplierAddress method
        suppliersAPI.UpdateSupplierAddress _
            (supplierID, addressValue, cityValue, countryValue)
    Next
End Sub

Quando o utilizador clica num dos botões Atualizar Tudo, o método UpdateAllSupplierAddresses itera por cada DataListItem na Suppliers DataList e chama o método SuppliersBLL da classe UpdateSupplierAddress, passando os valores correspondentes. Um valor não inserido para morada, cidade ou país/região constitui um valor de Nothing para UpdateSupplierAddress (em vez de uma cadeia de caracteres em branco), o que resulta em uma operação de NULL para os campos do registo subjacentes.

Observação

Como melhoria, convém adicionar um controlo web de rótulo de estado à página, que fornece uma mensagem de confirmação após a execução da atualização em lote.

Atualizando apenas os endereços que foram modificados

O algoritmo de atualização em lote usado para este tutorial chama o UpdateSupplierAddress método para cada fornecedor na DataList, independentemente de suas informações de endereço 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. Por exemplo, se você usar gatilhos para registrar todos os UPDATE s na Suppliers tabela em uma tabela de auditoria, sempre que um usuário clicar no botão Atualizar tudo, um novo registro de auditoria será criado para cada fornecedor no sistema, independentemente de o usuário ter feito alterações.

As classes ADO.NET DataTable e DataAdapter são projetadas para oferecer suporte a atualizações em lote onde apenas os registos modificados, eliminados e novos causam qualquer comunicação com o banco de dados. Cada linha na DataTable tem uma RowState propriedade que indica se a linha foi adicionada à DataTable, excluída dela, modificada ou permanece inalterada. Quando uma DataTable é preenchida inicialmente, todas as linhas são marcadas inalteradas. A alteração do valor de qualquer coluna numa linha marcará a linha como modificada.

Na classe SuppliersBLL, atualizamos as informações de endereço do fornecedor especificado lendo primeiro o registro único do fornecedor em um SuppliersDataTable e, em seguida, definimos os valores das colunas Address, City e Country usando o seguinte código:

Public Function UpdateSupplierAddress _
    (supplierID As Integer, address As String, city As String, country As String) _
    As Boolean
    Dim suppliers As Northwind.SuppliersDataTable = _
        Adapter.GetSupplierBySupplierID(supplierID)
    If suppliers.Count = 0 Then
        ' no matching record found, return false
        Return False
    Else
        Dim supplier As Northwind.SuppliersRow = suppliers(0)
        If address Is Nothing Then
            supplier.SetAddressNull()
        Else
            supplier.Address = address
        End If
        If city Is Nothing Then
            supplier.SetCityNull()
        Else
            supplier.City = city
        End If
        If country Is Nothing Then
            supplier.SetCountryNull()
        Else
            supplier.Country = country
        End If
        ' Update the supplier Address-related information
        Dim rowsAffected As Integer = Adapter.Update(supplier)
        ' Return true if precisely one row was updated, otherwise false
        Return rowsAffected = 1
    End If
End Function

Este código atribui de forma simples os valores de endereço, cidade e país/região passados ao SuppliersRow no SuppliersDataTable, independentemente de os valores terem ou não sido alterados. Essas modificações fazem com que a SuppliersRow propriedade s seja marcada RowState como modificada. Quando o método Data Access Layer s Update é chamado, ele vê que o SupplierRow foi modificado e, portanto, envia um UPDATE comando para o banco de dados.

Imagine, no entanto, que adicionamos código a esse método para atribuir apenas os valores de endereço, cidade e país/região passados se eles forem diferentes dos SuppliersRow valores s existentes. No caso em que o endereço, cidade e país/região são os mesmos que os dados existentes, nenhuma alteração será feita e o SupplierRow s RowState será deixado marcado como inalterado. O resultado final é que, quando o método DAL s Update é chamado, nenhuma chamada de banco de dados será feita porque o SuppliersRow não foi modificado.

Para implementar esta alteração, substitua as declarações que atribuem os valores de endereço, cidade e país/região de forma automática pelo seguinte código:

' Only assign the values to the SupplierRow's column values if they differ
If address Is Nothing AndAlso Not supplier.IsAddressNull() Then
    supplier.SetAddressNull()
ElseIf (address IsNot Nothing AndAlso supplier.IsAddressNull) _
    OrElse (Not supplier.IsAddressNull() AndAlso _
                String.Compare(supplier.Address, address) <> 0) Then
    supplier.Address = address
End If
If city Is Nothing AndAlso Not supplier.IsCityNull() Then
    supplier.SetCityNull()
ElseIf (city IsNot Nothing AndAlso supplier.IsCityNull) _
    OrElse (Not supplier.IsCityNull() AndAlso _
                String.Compare(supplier.City, city) <> 0) Then
    supplier.City = city
End If
If country Is Nothing AndAlso Not supplier.IsCountryNull() Then
    supplier.SetCountryNull()
ElseIf (country IsNot Nothing AndAlso supplier.IsCountryNull) _
    OrElse (Not supplier.IsCountryNull() AndAlso _
                String.Compare(supplier.Country, country) <> 0) Then
    supplier.Country = country
End If

Com esse código adicionado, o método DAL s Update envia uma UPDATE instrução para o banco de dados apenas para os registros cujos valores relacionados ao endereço foram alterados.

Como alternativa, podemos controlar se há diferenças entre os campos de endereço passados e os dados do banco de dados e, se não houver, simplesmente ignorar a chamada para o método DAL s Update . Esta abordagem funciona bem se estiver a usar o método direto DB, uma vez que um método direto DB não recebe uma SuppliersRow instância cuja RowState pode ser verificada para determinar se é realmente necessária uma chamada ao banco de dados.

Observação

Cada vez que o UpdateSupplierAddress método é invocado, uma chamada é feita para o banco de dados para recuperar informações sobre o registro atualizado. Em seguida, se houver alterações nos dados, outra chamada para o banco de dados será feita para atualizar a linha da tabela. Esse fluxo de trabalho pode ser otimizado criando uma UpdateSupplierAddress sobrecarga de método que aceite uma EmployeesDataTable instância que tenha todas as alterações da BatchUpdate.aspx página. Em seguida, ele poderia fazer uma chamada para o banco de dados para obter todos os registros da Suppliers tabela. Os dois conjuntos de resultados poderiam então ser enumerados e apenas os registos onde ocorreram alterações poderiam ser atualizados.

Resumo

Neste tutorial, vimos como criar uma DataList totalmente editável, permitindo que um usuário modifique rapidamente as informações de endereço para vários fornecedores. Começamos definindo a interface de edição de um controle Web TextBox para o endereço do fornecedor, cidade e valores de país/região no DataList s ItemTemplate. Em seguida, adicionamos os botões Atualizar tudo acima e abaixo da DataList. Depois de o utilizador fazer as suas alterações e clicar num dos botões de Atualizar Tudo, os DataListItem são enumerados e é feita uma chamada ao método SuppliersBLL da classe UpdateSupplierAddress.

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 Zack Jones e Ken Pespisa. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.