Partilhar via


Exclusão em Lote (VB)

por Scott Mitchell

Descarregar PDF

Saiba como excluir vários registros de banco de dados em uma única operação. Na Camada de Interface do Usuário, nos baseamos em um GridView aprimorado criado em um tutorial anterior. Na Camada de Acesso a Dados, encapsulamos as várias operações de Exclusão dentro de uma transação para garantir que todas as exclusões sejam bem-sucedidas ou todas as exclusões sejam revertidas.

Introdução

O tutorial anterior explorou como criar uma interface de edição em lote usando um GridView totalmente editável. Em situações em que os usuários geralmente editam muitos registros ao mesmo tempo, uma interface de edição em lote exigirá muito menos postbacks e opções de contexto de teclado para mouse, melhorando assim a eficiência do usuário final. Esta técnica é igualmente útil para páginas onde é comum que os utilizadores eliminem muitos registos de uma só vez.

Qualquer pessoa que tenha usado um cliente de e-mail on-line já está familiarizada com uma das interfaces de exclusão em lote mais comuns: uma caixa de seleção em cada linha de uma grade com um botão correspondente Excluir todos os itens marcados (consulte a Figura 1). Este tutorial é bastante curto porque já fizemos todo o trabalho duro em tutoriais anteriores na criação da interface baseada na Web e um método para excluir uma série de registros como uma única operação atômica. No tutorial Adicionando uma coluna de caixas de seleção GridView , criamos um GridView com uma coluna de caixas de seleção e, no tutorial Encapsulando modificações de banco de dados dentro de um tutorial de transação , criamos um método na BLL que usaria uma transação para excluir um List<T> dos ProductID valores. Neste tutorial, vamos desenvolver e mesclar as nossas experiências anteriores para criar um exemplo funcional de eliminação em lote.

Cada linha inclui uma caixa de seleção

Figura 1: Cada linha inclui uma caixa de seleção (Clique para visualizar a imagem em tamanho real)

Etapa 1: Criando a interface de exclusão em lote

Como já criamos a interface de exclusão em lote no tutorial Adicionando uma coluna GridView de caixas de seleção , podemos simplesmente copiá-la para BatchDelete.aspx em vez de criá-la do zero. Comece por abrir a BatchDelete.aspx página na BatchData pasta e a CheckBoxField.aspx página na EnhancedGridView pasta. Na página CheckBoxField.aspx, vá para a visualização "Source" e copie a marcação entre as tags <asp:Content> como mostrado na Figura 2.

Copie a marcação declarativa de CheckBoxField.aspx para a área de transferência

Figura 2: Copie a marcação declarativa de CheckBoxField.aspx para a área de transferência (Clique para visualizar a imagem em tamanho real)

Em seguida, vá para a visualização do código-fonte em BatchDelete.aspx e cole o conteúdo da área de transferência dentro das tags <asp:Content>. Também copie e cole o código de dentro da classe code-behind em CheckBoxField.aspx.vb para dentro da classe code-behind em BatchDelete.aspx.vb (o manipulador de eventos do botão DeleteSelectedProducts, o método Click e os manipuladores de eventos para os botões ToggleCheckState e Click). Depois de copiar esse conteúdo, a classe code-behind da BatchDelete.aspx página deve conter o seguinte código:

Partial Class BatchData_BatchDelete
    Inherits System.Web.UI.Page
    Protected Sub DeleteSelectedProducts_Click(sender As Object, e As EventArgs) _
        Handles DeleteSelectedProducts.Click
        
        Dim atLeastOneRowDeleted As Boolean = False
        ' Iterate through the Products.Rows property
        For Each row As GridViewRow In Products.Rows
            ' Access the CheckBox
            Dim cb As CheckBox = row.FindControl("ProductSelector")
            If cb IsNot Nothing AndAlso cb.Checked Then
                ' Delete row! (Well, not really...)
                atLeastOneRowDeleted = True
                ' First, get the ProductID for the selected row
                Dim productID As Integer = _
                    Convert.ToInt32(Products.DataKeys(row.RowIndex).Value)
                ' "Delete" the row
                DeleteResults.Text &= String.Format _
                    ("This would have deleted ProductID {0}<br />", productID)
                '... To actually delete the product, use ...
                ' Dim productAPI As New ProductsBLL
                ' productAPI.DeleteProduct(productID)
                '............................................
            End If
        Next
        ' Show the Label if at least one row was deleted...
        DeleteResults.Visible = atLeastOneRowDeleted
    End Sub
    Private Sub ToggleCheckState(ByVal checkState As Boolean)
        ' Iterate through the Products.Rows property
        For Each row As GridViewRow In Products.Rows
            ' Access the CheckBox
            Dim cb As CheckBox = row.FindControl("ProductSelector")
            If cb IsNot Nothing Then
                cb.Checked = checkState
            End If
        Next
    End Sub
    Protected Sub CheckAll_Click(sender As Object, e As EventArgs) _
        Handles CheckAll.Click
        ToggleCheckState(True)
    End Sub
    Protected Sub UncheckAll_Click(sender As Object, e As EventArgs) _
        Handles UncheckAll.Click
        ToggleCheckState(False)
    End Sub
End Class

Depois de copiar a marcação declarativa e o código-fonte, reserve um momento para testá-lo BatchDelete.aspx visualizando-o através de um navegador. Você verá um GridView que lista os dez primeiros produtos, com cada linha listando o nome, a categoria e o preço do produto, e uma caixa de seleção. Deve haver três botões: Verificar tudo, Desmarcar tudo e Excluir produtos selecionados. Clicar no botão Verificar tudo seleciona todas as caixas de seleção, enquanto Desmarcar tudo desmarca todas as caixas de seleção. Clicar em Excluir Produtos Selecionados exibe uma mensagem que lista os ProductID valores dos produtos selecionados, mas não exclui os produtos.

A interface do CheckBoxField.aspx foi movida para BatchDeleting.aspx

Figura 3: A interface foi movida CheckBoxField.aspx para BatchDeleting.aspx (Clique para visualizar a imagem em tamanho real)

Etapa 2: Excluindo os produtos verificados usando transações

Com a interface de exclusão em lote copiada com sucesso para BatchDeleting.aspx, tudo o que resta é atualizar o código para que o botão Eliminar Produtos Selecionados elimine os produtos selecionados utilizando o método DeleteProductsWithTransaction na classe ProductsBLL. Esse método, adicionado no tutorial Encapsulando Modificações de Banco de Dados Dentro de uma Transação, aceita como entrada um List(Of T) de ProductID valores e exclui cada ProductID correspondente no âmbito de uma transação.

O manipulador de eventos do botão DeleteSelectedProducts atualmente utiliza o seguinte ciclo Click para iterar por cada linha do GridView:

' Iterate through the Products.Rows property
For Each row As GridViewRow In Products.Rows
    ' Access the CheckBox
    Dim cb As CheckBox = row.FindControl("ProductSelector")
    If cb IsNot Nothing AndAlso cb.Checked Then
        ' Delete row! (Well, not really...)
        atLeastOneRowDeleted = True
        ' First, get the ProductID for the selected row
        Dim productID As Integer = _
            Convert.ToInt32(Products.DataKeys(row.RowIndex).Value)
        ' "Delete" the row
        DeleteResults.Text &= String.Format _
            ("This would have deleted ProductID {0}<br />", productID)
        '... To actually delete the product, use ...
        ' Dim productAPI As New ProductsBLL
        ' productAPI.DeleteProduct(productID)
        '............................................
    End If
Next

Para cada linha, o ProductSelector controle Web CheckBox é referenciado programaticamente. Se estiver marcada, a linha s ProductID será recuperada da DataKeys coleção e a DeleteResults propriedade Label s Text será atualizada para incluir uma mensagem indicando que a linha foi selecionada para exclusão.

Na verdade, o código acima não exclui nenhum registro, pois a chamada para o método s ProductsBLL da Delete classe é comentada. Se essa lógica de exclusão fosse aplicada, o código excluiria os produtos, mas não dentro de uma operação atômica. Ou seja, se as primeiras exclusões na sequência fossem bem-sucedidas, mas uma posterior falhasse (talvez devido a uma violação de restrição de chave estrangeira), uma exceção seria lançada, mas os produtos já excluídos permaneceriam excluídos.

A fim de assegurar a atomicidade, precisamos usar ao invés o método ProductsBLL da classe DeleteProductsWithTransaction. Como esse método aceita uma lista de ProductID valores, precisamos primeiro compilar essa lista da grade e, em seguida, passá-la como um parâmetro. Primeiro, criamos uma instância do List(Of T) tipo Integer. Dentro do loop For Each, precisamos adicionar os valores dos produtos selecionados ProductID a este List(Of T). Após o loop, este List(Of T) deve ser passado para o método ProductsBLL da classe DeleteProductsWithTransaction. Atualize o DeleteSelectedProducts manipulador de eventos Button s Click com o seguinte código:

Protected Sub DeleteSelectedProducts_Click(sender As Object, e As EventArgs) _
    Handles DeleteSelectedProducts.Click
    
    ' Create a List to hold the ProductID values to delete
    Dim productIDsToDelete As New System.Collections.Generic.List(Of Integer)
    ' Iterate through the Products.Rows property
    For Each row As GridViewRow In Products.Rows
        ' Access the CheckBox
        Dim cb As CheckBox = CType(row.FindControl("ProductSelector"), CheckBox)
        If cb IsNot Nothing AndAlso cb.Checked Then
            ' Save the ProductID value for deletion
            ' First, get the ProductID for the selected row
            Dim productID As Integer = _
                Convert.ToInt32(Products.DataKeys(row.RowIndex).Value)
            ' Add it to the List...
            productIDsToDelete.Add(productID)
            ' Add a confirmation message
            DeleteResults.Text &= String.Format _
                ("ProductID {0} has been deleted<br />", productID)
        End If
    Next
    ' Call the DeleteProductsWithTransaction method and show the Label 
    ' if at least one row was deleted...
    If productIDsToDelete.Count > 0 Then
        Dim productAPI As New ProductsBLL()
        productAPI.DeleteProductsWithTransaction(productIDsToDelete)
        DeleteResults.Visible = True
        ' Rebind the data to the GridView
        Products.DataBind()
    End If
End Sub

O código atualizado cria um List(Of T) do tipo Integer (productIDsToDelete) e o preenche com os ProductID valores a serem excluídos. Após o For Each loop, se houver pelo menos um produto selecionado, o método da classe ProductsBLL é chamado e esta lista é passada. O DeleteResults Label também é exibido e os dados são recarregados para o GridView (para que os registros recentemente excluídos não apareçam mais como linhas na grelha).

A Figura 4 mostra o GridView depois que várias linhas foram selecionadas para exclusão. A Figura 5 mostra a tela imediatamente após o botão Excluir produtos selecionados ter sido clicado. Observe que na Figura 5 os ProductID valores dos registros excluídos são exibidos no Label abaixo do GridView e essas linhas não estão mais no GridView.

Os produtos selecionados serão excluídos

Figura 4: Os produtos selecionados serão excluídos (Clique para visualizar a imagem em tamanho real)

Os valores de ProductID de produtos excluídos estão listados abaixo do GridView

Figura 5: Os valores de produtos ProductID excluídos estão listados abaixo do GridView (Clique para visualizar a imagem em tamanho real)

Observação

Para testar a DeleteProductsWithTransaction atomicidade do método, adicione manualmente uma entrada para um produto na tabela e, em Order Details seguida, tente eliminar esse mesmo produto (junto com outros). Você receberá uma violação de restrição de chave estrangeira ao tentar excluir o produto com um pedido associado, mas observe como as exclusões de outros produtos selecionados são revertidas.

Resumo

Criar uma interface de exclusão em lote envolve adicionar um GridView com uma coluna de caixas de seleção e um controle Web de botão que, ao ser clicado, excluirá todas as linhas selecionadas como uma única operação atômica. Neste tutorial, construímos essa interface juntando o trabalho feito em dois tutoriais anteriores, Adicionando uma coluna GridView de caixas de seleção e Encapsulando modificações de banco de dados dentro de uma transação. No primeiro tutorial criamos um GridView com uma coluna de caixas de seleção e no segundo implementamos um método na BLL que, quando passado um List(Of T) dos ProductID valores, excluía todos eles dentro do escopo de uma transação.

No próximo tutorial, criaremos uma interface para executar inserções em lote.

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 para este tutorial foram Hilton Giesenow e Teresa Murphy. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.