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


Este é um artigo para iniciantes e mostra 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 será o controle ListView.

O cenário será realizar a manutenção de usuários que estão armazenados em uma tabela Usuarios no banco de dados chamado Controle.mdb.

Vemos na figura abaixo a estrutura da tabela Usuarios e alguns dados que eu vou usar para testar o projeto.

Eu poderia realizar a tarefa de manutenção de dados usando diversas técnicas mas vou usar os recursos da ADO .NET e trabalhar com uma camada de acesso a dados e uma camada de negócios separando assim as funcionalidades da nossa aplicação. Mesmo em projetos pequenos esta é uma boa prática a qual você deve se habituar.

Embora o Domain Drive Design(DDD)tenha uma filosofia completamente diferente da que estamos seguindo (estamos começando com o banco de dados e não com o foco no negócio), nosso projeto vai procurar seguir as boas práticas usando os recursos da ADO .NET usando o Visual Basic 2010 Express Edition.

Antes de iniciar o projeto vamos dar uma olhada no formulário principal e explicar algumas funcionalidades do mesmo:

Abaixo temos o formulário principal do projeto onde é realizada a manutenção dos usuários da tabela Usuarios:

O Controle ListView esta sendo usado para exibir e manipular os dados de forma que ao clicar em uma linha do controle os dados são exibidos nas caixas de texto do formulário. Além disso vamos aplicar o efeito zebrado no controle e formatar as colunas.

Estamos usando também uma camada de acesso a dados simples com os recursos da ADO .NET (sem LINQ nem Entity Framework) e uma camada de negócios de forma a ter uma arquitetura em 3 camadas onde:

Vamos então criar um projeto do tipo Windows Forms Application no Visual Basic 2010 Express Edition no menu File -> New Project, com o nome SistemaControleAcesso;

Feito isso vamos criar uma pasta no projeto chamada Dados onde iremos colocar o banco de dados Controle.mdb. Clique com o botão direito do mouse sobre o nome do projeto e selecione Add-> New Folder e informe o nome Dados;

A seguir no menu Project selecione Add Class e inclua um template Class com o nome AcessoHelper.vb;

Neste arquivo iremos definir a nossa camada de acesso a dados. Ela será simples mas bem funcional.

Vamos criar uma camada de acesso a dados que no futuro poderá ser modificada para trabalhar com outros banco de dados como o SQL Server e um banco de dados ODBC embora no projeto estejamos usando o Microsoft Access por questão de simplicidade.

Abra o arquivo AcessoHelper.vb e defina no seu início os seguintes namespaces:

Imports System
Imports System.Data
Imports System.Data.Common
Imports System.Data.SqlClient
Imports System.Data.Odbc
Imports System.Data.OleDb
Imports System.IO

A seguir vamos definir a classe AcessoHelper implementando a interface IDisposable. Geralmente implementamos esta interface quando vamos tratar com tipos não gerenciados cono conexões de banco de dados e mesmo com código gerenciado como as classe .NET como System.IO.FileStream e assim termos mais segurança de que os objetos serão liberados após sua utilização pelo coletor de lixo.

Dessa forma vamos declarar a nossa classe da seguinte forma:

Public Class AcessoHelper
       Implements IDisposable

Fazendo isso temos que implementar o seguinte método na classe:

Public Sub Dispose1() Implements System.IDisposable.Dispose
  objConnection.Close()
  objConnection.Dispose()
  objCommand.Dispose()
End Sub

A seguir vamos declarar as variáveis objetos que iremos usar no projeto :

Private strConnectionString As String
Private objConnection As DbConnection
Private objCommand As DbCommand
Private objFactory As DbProviderFactory = Nothing

Note que estamos usando a classe DbProviderFactory que representa um conjunto de métodos para criação de instâncias de implementação de provedores das classes de fonte de dados. Fizemos isso pois no futuro poderemos expandir a classe para ser usada com outros banco de dados sem ter que alterar muito o código.

O próximo passo é definir uma enumeração para tratar a conexão definindo se vamos fechá-la ou deixá-la aberta:

Public Enum ConnectionState
    MantemConexaoAberta
    FechaConexaoAoSair
End Enum

Nota: Uma Enumeration oferece uma maneira fácil de trabalhar com conjunto de dados que estão relacionados a constantes. Assim , um Enumeration ou Enum é um nome simbólico para um conjunto de valores.

Após essas definições vamos criar o construtor da nossa classe conforme o código abaixo:

Public Sub New()
   objFactory = OleDbFactory.Instance
   objConnection = objFactory.CreateConnection
   objCommand = objFactory.CreateCommand
   objConnection.ConnectionString = GetStringConnection()
   objCommand.Connection = objConnection
End Sub

Nota: O construtor é uma rotina que é invocada quando uma instância de uma classe é criada. No VB.NET esta rotina precisa ter o nome New para identificar o construtor.

O construtor inicia os objetos e define a string de conexão e a conexão com o banco de dados. O próximo passo é definir o método GetStringConnection() que obtém a string de conexão:

Public Function GetStringConnection() As String
   Dim caminhoBD As String = GetCaminhoBD() & "\Dados\Controle.mdb"
   Dim strConexao As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & caminhoBD & ";Mode=ReadWrite;Persist Security Info=False"
   
' Retorna a string de conexão
   Return strConexao
End Function

Obs1: Este método retorna a string de conexão que foi definida via código o melhor seria colocar a string de conexão no arquivo App.Config e usar a classe ConfigurationManager para obter a string de conexão deste arquivo. Para isso teremos que incluir o namespace: System.Configuration e uma referência no projeto a System.Configuration e usar a seguinte linha de código: Dim strconexao = ConfigurationManager.ConnectionStrings("connectionstring").ConnectionString()

Obs2: Podemos ainda usar o recurso My para obter a string de conexão definida no arquivo App.Config usando o seguinte código:
Dim strconexao as String = My.Settings.ControleAcessoConnectionString

Vamos definir o método GetCaminhoBD() que vai definir o caminho do banco de dados que estamos usando. Lembre que o banco de dados esta na pasta Dados do projeto.

Public Shared Function GetCaminhoBD() As String

Dim caminhoArquivo As String = Application.StartupPath

If caminhoArquivo.IndexOf("\bin\Debug") <> -1 Then
     caminhoArquivo = caminhoArquivo.Replace("\bin\Debug", "")
ElseIf caminhoArquivo.IndexOf("\bin\Release") <> -1 Then
    caminhoArquivo = caminhoArquivo.Replace("\bin\Release", "")
End If

Return caminhoArquivo
End Function

Neste código retornamos o caminho da aplicação de forma que o caminho do banco de dados será definido a partir da pasta \Dados que criamos no projeto.

A próxima etapa será definir os métodos para acessar e persistir informações no banco de dados. Para tornar as coisas mais simples eu só vou definir os métodos que o projeto irá usar e o nosso projeto irá realizar as seguintes operações:

A seguir temos os métodos ExecuteNonQuery definidos na classe AcessoHelper da camada de acesso a dados:

 Public Function ExecuteNonQuery(ByVal query As String) As Integer
        Return ExecuteNonQuery(query, CommandType.Text, ConnectionState.FechaConexaoAoSair)
    End Function

    Public Function ExecuteNonQuery(ByVal query As String, ByVal commandtype As CommandType) As Integer
        Return ExecuteNonQuery(query, commandtype, ConnectionState.FechaConexaoAoSair)
    End Function

    Public Function ExecuteNonQuery(ByVal query As String, ByVal connectionstate As ConnectionState) As Integer
        Return ExecuteNonQuery(query, CommandType.Text, connectionstate)
    End Function

    Public Function ExecuteNonQuery(ByVal query As String, ByVal commandtype As CommandType, ByVal connectionstate As ConnectionState) As Integer
        objCommand.CommandText = query
        objCommand.CommandType = commandtype
        Dim i As Integer = -1
        Try
            If objConnection.State = System.Data.ConnectionState.Closed Then
                objConnection.Open()
            End If
            i = objCommand.ExecuteNonQuery
        Catch ex As Exception
            Throw (ex)
        Finally
            objCommand.Parameters.Clear()
            If connectionstate = connectionstate.FechaConexaoAoSair Then
                objConnection.Close()
            End If
        End Try
        Return i
 End Function

Porque definimos 4 métodos ExecuteNonQuery ?

Definimos 4 métodos sobrecarregados para ter mais flexibilidade de forma a podemos passar para o métodos parâmetros diferentes conforme a nossa necessidade. Assim temos:

Nosso projeto iremos usar somente a primeira opção mas eu resolvi deixar os demais métodos para você perceber uma característica de uma linguagem orientada a objetos : a sobrecarga de métodos.

A seguir temos a definição dos métodos ExecuteReader da camada de acesso a dados:

    Public Function ExecuteReader(ByVal query As String) As DbDataReader
        Return ExecuteReader(query, CommandType.Text, ConnectionState.FechaConexaoAoSair)
    End Function

    Public Function ExecuteReader(ByVal query As String, ByVal commandtype As CommandType) As DbDataReader
        Return ExecuteReader(query, commandtype, ConnectionState.FechaConexaoAoSair)
    End Function

    Public Function ExecuteReader(ByVal query As String, ByVal connectionstate As ConnectionState) As DbDataReader
        Return ExecuteReader(query, CommandType.Text, connectionstate)
    End Function

    Public Function ExecuteReader(ByVal query As String, ByVal commandtype As CommandType, ByVal connectionstate As ConnectionState) As DbDataReader
        objCommand.CommandText = query
        objCommand.CommandType = commandtype
        Dim reader As DbDataReader = Nothing
        Try
            If objConnection.State = System.Data.ConnectionState.Closed Then
                objConnection.Open()
            End If
            If connectionstate = connectionstate.FechaConexaoAoSair Then
                reader = objCommand.ExecuteReader(CommandBehavior.CloseConnection)
            Else
                reader = objCommand.ExecuteReader
            End If
        Catch ex As Exception
            Throw (ex)
        Finally
            objCommand.Parameters.Clear()
        End Try
        Return reader
    End Function

Aqui também definimos 4 métodos sobrecarregados mas na verdade o projeto irá usar somente o primeiro onde passamos somente a string de consulta para o método.

Além destes poderíamos definir também os métodos :

Obs: No projeto estes métodos estão comentados. Para usá-los basta descomentar.

Como estamos vamos usar parâmetros nas instruções SQL e consultas precisamos definir um método para podermos passar os parâmetros que serão usados nas instruções SQL. Para isso vamos criar o método AddParameter() conforme mostrado a seguir:

   Public Function AddParameter(ByVal name As String, ByVal value As Object) As Integer
        Dim p As DbParameter = objFactory.CreateParameter
        p.ParameterName = name
        p.Value = value
        Return objCommand.Parameters.Add(p)
    End Function

    Public Function AddParameter(ByVal parameter As DbParameter) As Integer
        Return objCommand.Parameters.Add(parameter)
    End Function

Para encerrar vamos definir um método para gerar um Hash da senha de forma que vamos armazenar não o texto da senha mas o seu HASH aumentando assim a segurança da informação. Segue abaixo o código do método GerarHash que obtém um texto e retorna um hash do mesmo :

 Public Function GerarHash(ByVal Valor As String) As String
        Dim Sha As New System.Security.Cryptography.SHA1Managed
        Sha.ComputeHash(System.Text.Encoding.Default.GetBytes(Valor))
        Return Convert.ToBase64String(Sha.Hash)
    End Function

Nota: Um hash é uma seqüencia de letras ou números geradas por um algorítmo de Hash. Na criptografia, o hash serve para garantir a integridade da mensagem, onde o gerador (ou emissor) da mensagem, submete-a a um algoritmo hash, o qual produzirá um valor hash.

Com esses métodos já temos a camada de acesso a dados pronta para nos dar o suporte necessário para consultar e persistir informações.

A próxima etapa é 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 as demais camadas para acessar e persistir informações dos usuários.

Aguarde a continuação do artigo em : VB .NET- Manutenção de dados com ListView, ADO .NET usando DAL - II

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

Referências:

José Carlos Macoratti