VB .NET- Manutenção de dados com ListView, ADO .NET usando DAL - II


Na primeira parte deste artigo (escrita a alguns meses atrás) - VB .NET- Manutenção de dados com ListView, ADO .NET usando DAL - eu apresentei a proposta de criar como realizar a manutenção de dados usando a ADO .NET com a linguagem Visual Basic em um projeto Windows Forms onde o controle central era o controle ListView.

A proposta incluía adotar as boas práticas criando a aplicação em camadas e na primeira parte eu já havia criado a classe AcessoHelper que continha os métodos da camada de acesso a dados prontos para nos dar o suporte necessário para consultar e persistir informações.

A próxima etapa seria definir uma camada de negócios para receber as instruções da camada de interface e por último definir a camada de interface e criar as requisições necessárias às demais camadas para acessar e persistir informações dos usuários.

Como me envolvi em outros projetos mais importantes acabei esquecendo de continuar o projeto e como recebi muitos emails para continuar o projeto eu decidi fazê-lo sob algumas condições.

Primeiro gostaria de dizer que o projeto é bem básico e voltado para quem já tem um conhecimento sobre ADO .NET e deseja melhorar a arquitetura de seus projetos adotando as boas práticas. Eu dou uma introdução nesse assunto criando a camada de acesso a dados de uma forma bem simples, sem usar interfaces nem classes abstratas mas apenas um classe concreta que implementa a interface IDisposable. Isso é o básico, mas já é um avanço se comparado com a metodologia de colocar o código de acesso a dados no formulário da aplicação.

Bem, como dizia eu vou continuar o artigo mas para não tomar muito tempo eu vou simplificá-lo e não vou criar a camada de negócios simplesmente por que não estou com tempo e por que nesta camada colocamos as regras de negócio e validações de negócio e nossa aplicação é um simples cadastro de usuários onde estamos realizando as operações CRUD. Mesmo sem usar a camada de negócios seria bom criá-la deixando-a pronta para uma eventual mudança dos requisitos e surgimento de novas regras de negócio. Eu não vou fazer isso vou instanciar a camada de acesso a dados diretamente na camada de interface (violando assim as boas práticas).

Na verdade o projeto era mais ambicioso , eu pretendia criar um controle de acessos básico onde poderíamos atribuir os acessos aos formulários da aplicação aos usuários. O projeto completo já contém os formulário prontos para implementar esta funcionalidade.

Feitas as explicações vamos continuar com a manutenção de usuários implementando as funcionalidades CRUD (Create, Update, Delete)...

Implementando as operações CRUD

Para implementar as funcionalidades de inclusão, alteração e exclusão eu vou criar uma nova classe chamada UsuarioDAL e nesta classe definir os métodos específicos para incluir, excluir, alterar e procurar usuários. Essa classe ira conter os seguintes métodos:

No menu Project selecione Add Class e inclua um template Class com o nome UsuarioDAL.vb;

O código desta classe é dado a seguir:

Imports System.Data
Imports System.Data.OleDb

Public Class UsuarioDAL
    Public db As New AcessoHelper()

    Public Sub cadastraUsuario(ByVal nome As String, ByVal cargo As String, ByVal senha As String)
        Try
            Dim sql As String = "Insert Into Usuarios(nome,cargo,senha) values (@nome,@cargo,@senha)"
            db.AddParameter("@nome", nome)
            db.AddParameter("@cargo", cargo)
            db.AddParameter("@senha", senha)
            db.ExecuteNonQuery(sql)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Sub alterarUsuario(ByVal nome As String, ByVal cargo As String, ByVal senha As String, ByVal usuarioid As Integer)
        Try
            Dim sql As String = "Update Usuarios set nome=@nome, cargo=@caro, senha=@senha where usuarioid =@usuarioid"
            db.AddParameter("@nome", nome)
            db.AddParameter("@cargo", cargo)
            db.AddParameter("@senha", senha)
            db.AddParameter("@usuarioid", usuarioid)
            db.ExecuteNonQuery(sql)
            'MessageBox.Show("Usuário alterado com sucesso.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Sub excluirUsuario(ByVal usuarioid As Integer)
        Try
            Dim sql As String = "Delete From usuarios where usuarioid =@usuarioid"
            db.AddParameter("@usuarioid", usuarioid)
            db.ExecuteNonQuery(sql)
            'MessageBox.Show("Usuário alterado com sucesso.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Function Procurar(ByVal usuarioid As Integer) As OleDbDataReader
        Try
            Dim sql As String = "SELECT * FROM usuarios WHERE usuarioid=@usuarioid"
            db.AddParameter("@usuarioid", usuarioid)
            Return db.ExecuteReader(sql)
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Function ProcurarPorNome(ByVal nome As String) As Boolean
        Dim dr As OleDbDataReader = Nothing
        Try
            Dim sql As String = "SELECT * FROM usuarios WHERE nome=@nome"
            db.AddParameter("@nome", nome)
            dr = db.ExecuteReader(sql)
            If dr.HasRows Then
                Return True
            Else
                Return False
            End If
        Catch ex As Exception
            Throw ex
        Finally
            dr.Close()
        End Try
    End Function
    Public Function Selecionar() As OleDbDataReader
        Try
            Dim sql As String = "SELECT * FROM usuarios"
            Return db.ExecuteReader(sql)
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Sub PreencheListView(ByRef cListView As ListView, ByRef dados As OleDbDataReader)

        Dim lvwColumn As ColumnHeader
        Dim itmListItem As ListViewItem
        Dim shtCntr As Short

        cListView.Clear()
        For shtCntr = 0 To dados.FieldCount() - 1
            lvwColumn = New ColumnHeader()
            lvwColumn.Text = dados.GetName(shtCntr)
            cListView.Columns.Add(lvwColumn)
        Next

        Do While dados.Read
            itmListItem = New ListViewItem()
            itmListItem.Text = dados(0)

            For shtCntr = 1 To dados.FieldCount() - 1
                If dados.IsDBNull(shtCntr) Then
                    itmListItem.SubItems.Add("")
                Else
                    itmListItem.SubItems.Add(dados.GetString(shtCntr))
                End If
            Next shtCntr

            cListView.Items.Add(itmListItem)
        Loop
    End Sub

    Public Function gerarHashSenha(ByVal texto) As String
        Return db.GerarHash(texto)
    End Function
End Class

Esta classe utiliza os métodos definidos na classe AcessoHelper para realizar as operações CRUD no banco de dados.

Na figura abaixo temos uma visão das camadas usadas em nosso projeto:

Agora já podemos definir implementar na interface as chamadas aos métodos definidos nas classes UsuarioDAL e AcessoHelper.

Definindo o código da interface do Usuário

A nossa interface é o formulário frmUsuarios.vb que é composto pelos controles ListView, Button, Label e TextBox e cujo leiaute é mostrado na figura abaixo:

O formulário possui além dos botões de comando que implementa as funcionalidades que desejamos, algumas rotinas usadas na seleção e carga de dados.

No evento Load do formulário temos o código que define algumas características do ListView : a visão detalhes, a exibição das linhas de grade e o destaque da linha na seleção de um item.

A seguir é feita a chamada para as rotinas PreencheListView() e AlternarCoresdeFundo que preenche o ListView e alterna as cores de exibição no controle.

Private Sub frmUsuarios_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Try
            With lvUsuarios
                .View = View.Details
                .FullRowSelect = True
                .GridLines = True
            End With
            PreencheListView(lvUsuarios)
            AlternarCoresdeFundo(lvUsuarios, Color.Aqua, Color.LightGreen)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

A rotina PreencheListView possui o seguinte código:

Public Sub PreencheListView(ByRef cListView As ListView)

        Dim lvwColumn As ColumnHeader
        Dim itmListItem As ListViewItem
        'isso não deveria estar presente na camada de interface
        'por pura preguiça em criar uma rotina deixei este código aqui
        Dim dados As OleDbDataReader = acc.Selecionar()

        Dim shtCntr As Short
        Dim incremento As Integer = 0
        cListView.Clear()
        For shtCntr = 0 To dados.FieldCount() - 1
            lvwColumn = New ColumnHeader()
            lvwColumn.Text = dados.GetName(shtCntr)
            cListView.Columns.Add(lvwColumn.Text, 60 + incremento, HorizontalAlignment.Left)
            incremento = incremento + 30
        Next

        Do While dados.Read
            itmListItem = New ListViewItem()
            itmListItem.Text = dados(0)

            For shtCntr = 1 To dados.FieldCount() - 1
                If dados.IsDBNull(shtCntr) Then
                    itmListItem.SubItems.Add("")
                Else
                    itmListItem.SubItems.Add(dados.GetString(shtCntr))
                End If
            Next shtCntr

            cListView.Items.Add(itmListItem)
        Loop
        dados.Close()
    End Sub

O código da rotina AlterarCoresdeFundo é mostrada a seguir:

 Public Sub AlternarCoresdeFundo(ByVal lst As ListView, ByVal color1 As Color, ByVal color2 As Color)
        'percorre cada ListViewItem no ListView
        For Each item As ListViewItem In lst.Items
            If (item.Index Mod 2) = 0 Then
                item.BackColor = color1
            Else
                item.BackColor = color2
            End If
        Next
    End Sub

Quando é feita uma seleção no controle ListView os controles TextBox devem ser preenchidos com os respectivos valores e para isso usamos o evento SelectedIndexChanged do controle obtendo o código do item selecionado e chamando a rotina PreencheControles();

 Private Sub lvUsuarios_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lvUsuarios.SelectedIndexChanged
        Try
            If lvUsuarios.SelectedItems.Count > 0 Then
                'Dim i As Integer = Convert.ToInt32(lvUsuarios.SelectedItems(0).SubItems(0).Text)
                'Dim j As Integer = Convert.ToInt32(lvUsuarios.Items(i).Text)
                'codigo = Convert.ToInt32(lvUsuarios.FocusedItem.SubItems(0).Text)
                codigo = Convert.ToInt32(lvUsuarios.Items(lvUsuarios.SelectedIndices(0)).Text)
                PreencheControles(acc.Procurar(codigo))
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

O código da rotina PreencheControles que preenche cada caixa de texto com o valor o item selecionado é o seguinte:

Private Sub PreencheControles(ByVal dados As OleDbDataReader)
        Try
            Do While dados.Read
                txtUsuario.Text = dados("usuarioid")
                txtNome.Text = dados("nome")
                txtCargo.Text = dados("cargo")
                txtSenha.Text = dados("senha")
                senhaAtual = dados("senha")
            Loop
            dados.Close()
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning)
        End Try
    End Sub

Além disso temos a rotina ValidaDados que verifica se as caixas de texto estão vazias e cujo código vemos a seguir:

Private Function ValidaDados() As Boolean
        If txtNome.Text = String.Empty Or txtSenha.Text = String.Empty Or txtCargo.Text = String.Empty Then
            MessageBox.Show("Dados incompletos/inválidos...")
            Return False
        Else
            Return True
        End If
    End Function

Vejamos agora a implementação das funcionalidades Incluir, Atualizar e Excluir usuários no formulário.

Antes de iniciar devemos declarar as seguintes variáveis no início do formulário:

Dim acc As New UsuarioDAL
Dim codigo As Integer = 0
Dim senhaAtual As String = ""
Dim nomeAtual As String = ""

1 - Incluindo um usuário

O código existente no evento Click do botão Incluir é dado abaixo:

Private Sub btnIncluir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnIncluir.Click
        Try
            If ValidaDados() Then
                If acc.ProcurarPorNome(txtNome.Text) Then
                    MessageBox.Show("Já existe usuário cadastrado com este login. Tente outro nome para o login.", "Login já Cadastrado", MessageBoxButtons.OK, MessageBoxIcon.Information)
                    txtNome.Focus()
                    Return
                End If
                acc.cadastraUsuario(txtNome.Text, txtCargo.Text, acc.gerarHashSenha(txtSenha.Text))
                MessageBox.Show("Usuário incluido com sucesso.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                PreencheListView(lvUsuarios)
                AlternarCoresdeFundo(lvUsuarios, Color.Aqua, Color.LightGreen)
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

O código após validar os dados informados pelo usuário verifica se o não existe um nome de login já cadastrado para o nome informado usando a rotina ProcurarPorNome da classe UsuarioDAL.

Para incluir o usuário foi chamada o método cadastraUsuario da classe UsuarioDAL.

2 - Alterando um usuário

O código existente no evento Click do botão Atualizar é mostrado a seguir:

Private Sub btnAtualizar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAtualizar.Click
        Try
            If ValidaDados() Then
                If Not nomeAtual.Equals(txtNome.Text) Then
                    If acc.ProcurarPorNome(txtNome.Text) Then
                        MessageBox.Show("Já existe usuário cadastrado com este login. Tente outro nome para o login.", "Login já Cadastrado", MessageBoxButtons.OK, MessageBoxIcon.Information)
                        txtNome.Focus()
                        Return
                    End If
                End If
                If senhaAtual.Equals(txtSenha.Text) Then
                    acc.alterarUsuario(txtNome.Text, txtCargo.Text, txtSenha.Text, txtUsuario.Text)
                Else
                    acc.alterarUsuario(txtNome.Text, txtCargo.Text, acc.gerarHashSenha(txtSenha.Text), txtUsuario.Text)
                End If
                MessageBox.Show("Usuário atualizado com sucesso.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                PreencheListView(lvUsuarios)
                AlternarCoresdeFundo(lvUsuarios, Color.Aqua, Color.LightGreen)
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub

Para alterar um usuário primeiro validamos os dados informados para não permitir valores inválidos.

Em seguida verificamos se o nome esta sendo alterado (Not nomeAtual.Equals(txtNome.Text) e neste caso verificamos ainda se o nome já não esta cadastrado.

Devemos também verificar se a senha não esta sendo alterada (senhaAtual.Equals(txtSenha.Text) e se estiver devemos gerar o Hash para a nova senha informada.

Para alterar o usuário foi chamada o método alterarUsuario da classe UsuarioDAL.

3 - Excluindo um usuário

O código existente no evento Click do botão Excluir é exibido a seguir:

 Private Sub btnExcluir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExcluir.Click
        Dim resultado As DialogResult = MessageBox.Show("Confirma exclusão deste usuário ?", "Confirma Exclusão", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
        If resultado = DialogResult.Yes Then
            Try
                acc.excluirUsuario(txtUsuario.Text)
                MessageBox.Show("Usuário excluido com sucesso.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                PreencheListView(lvUsuarios)
                AlternarCoresdeFundo(lvUsuarios, Color.Aqua, Color.LightGreen)
            Catch ex As Exception
                MessageBox.Show("Erro ao excluir o usuário.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning)
            End Try
        End If
    End Sub

Para excluir um usuário foi chamada o método excluirUsuario da classe UsuarioDAL.

Executando o projeto iremos obter:

Com isso conclui o artigo e mostrei, embora com algumas simplificações (que você pode ajustar melhorando o código) como realizar as operações de manutenção de dados usando um controle ListView com ADO .NET em camadas.

Pegue o projeto completo aqui: SistemaControleAcesso.zip

Eu sei é apenas VB .NET, mas eu gosto...

Referências:

José Carlos Macoratti