VB .NET - Preenchendo controles de formulários a partir de um banco de dados - I


 Neste artigo vou mostrar como podemos preencher controles de formulários Windows Forms a partir de um banco de dados usando a linguagem VB .NET.

Ao desenvolver uma aplicação desktop usando o template Windows Forms que utiliza um banco de dados teremos que exibir os dados em controles de formulários como TextBox, Label, ComboBox, ListBox, DataGridView, ListView, etc.

É uma tarefa simples mas que pode confundir quem esta iniciando o seu aprendizado na plataforma .NET quer seja usando a linguagem VB .NET ou C#.

Este artigo é voltado para os iniciantes e mostra como podemos acessar dados e exibir informações em controles de formulários procurando adotar boas práticas de programação como a separação de responsabilidades. Nele vamos abordar os cenários mais comuns que podem ocorrer no dia a dia de um desenvolvedor VB .NET.

Quando temos que exibir informações em formulários Windows Forms temos que dividir essa tarefa em duas partes :

  1. Localizar e acessar os dados que desejamos exibir
  2. Exibir os dados no formulário com uma interface amigável e clara ao usuário

Na internet existem toneladas de exemplos de aplicações Windows Forms que acessam dados e exibem informações em controles de formulários, e, creio que 90% delas não respeitam a separação das responsabilidades e misturam o código de acesso a dados com a camada de apresentação geralmente incluindo esse código em eventos dos controles de formulário como Click ou Load. Essa técnica é conhecida como One-Click_Button ou OCB.

O acróstico OCB quer dizer one-click-button , e significa aquele programador que põe um botão no formulário e no seu evento Click (o evento Load também é muito usado nesta técnica) coloca centenas de linhas de código que procuram fazer praticamente tudo da funcionalidade implementada no formulário:  obter string de conexão, abrir conexão , acessar o banco de dados , criar objetos de acesso a dados , preencher os controles de formulário , e assim por diante...

Começar usando o técnica
OCB não é demérito para ninguém, continuar a usá-la ao longo dos anos sim. 

Temos assim uma aplicação que funciona mas que fere as boas práticas e que se torna difícil de manter, de reutilizar e de testar.

Para mostrar que podemos começar fazendo o certo desde o princípio, nesta série de artigos eu vou abordar a estratégia de acesso a dados usando ADO .NET e ferramentas ORM como Entity Framework e NHibernate de forma a criar uma camada de acesso a dados separada da camada de apresentação mostrando com isso as vantagens dessa abordagem.

Recursos usados:

Resistindo à tentação de usar os assistentes de acesso a dados

A plataforma .NET facilita muito o acesso e a apresentação de dados em formulários através de assistentes.

Basta criar uma nova fonte de dados e arrastar a tabela da fonte de dados para o formulário que você terá todos os controles gerados e a conexão criada juntamente com os recursos para incluir, alterar, excluir e consultar dados.

Então porque não usar ?

Esse processo facilita a sua vida no momento mas te oferece um projeto que mistura código de acesso a dados com camada de apresentação, não fornece uma validação de dados robusta e não permite a reutilização de código.

Ou seja você não tem controle sobre o processo, por isso utilize este recurso somente pequenos projetos  ou protótipos. Se você quer desenvolver aplicações comerciais robustas resista à tentação.

Cenário I - Acessando o MS Access com ADO .NET

Neste cenário vamos acessar um banco de dados Microsoft Access (.mdb) e exibir informações em controles TextBox de uma aplicação Windows Forms usando a tecnologia ADO .NET.

A primeira coisa que devemos fazer é definir qual banco de dados e quais tabelas desejamos acessar. Para este exemplo eu vou acessar o banco de dados Northwind.mdb e a tabela Customers.

Nota: Se você não possui o banco de dados Northwind.mdb, procure no Google por : 'Northwind.mdb download'. (Os scripts para a versão SQL Server pode ser baixada neste link: http://northwinddatabase.codeplex.com/ )

Vamos então definir uma conexão com este banco de dados abrindo o Visual Studio 2013 Express for windows desktop e a seguir abrindo a janela Database Explorer;

Nesta janela clique com o botão direito sobre Data Connections e a seguir em Add Connection;

Em Data Source clique no botão Change e selecione Microsoft Access DataBase File;

A seguir informe a pasta e o nome Northwind.mdb e clique no botão Test Connection para verificar a conexão;

Você deverá ver o banco de dados Northwind.mdb na janela DataBase Explorer conforme figura abaixo:

Agora temos que definir a string de conexão e para obter a string de conexão basta selecionar o banco de dados Northwind.mdb na janela DataBase Explorer e pressionar F4.

Na janela de propriedades em Connection String você verá a string de conexão conforme a figura abaixo:

Precisamos armazenar a string de conexão para podermos usá-la na criação da conexão com o banco de dados.

Você nunca deve armazenar a string de conexão no seu código isso pode te trazer problemas no futuro se a string de conexão for alterada. Um bom lugar para armazená-la é no arquivo App.Config da aplicação. E vamos fazer isso.

Vamos então criar a nossa solução...

Criando o projeto no Visual Studio 2013 Express

Abra o VS Express 2013 for Windows desktop e clique em New Project;

A seguir selecione a linguagem Visual Basic e o template Windows Forms Application;

Informe o nome Cenario1_MSAccess_AdoNet e clique no botão OK;

Agora abra o arquivo App.Config que foi criado e defina uma seção <connectionStrings> e nesta seção defina :

1- O nome da string de conexão em name : conexaoNorthwind
2- O seu valor em connectionString: "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\dados\NorthWind.mdb"
3- O nome do provedor que iremos usar. Para acessar o Microsoft Access usamos o provedor: System.Data.OleDb

Abaixo vemos os valores definidos no arquivo App.Config:

Dessa forma começamos bem pois com a string de conexão armazenada no arquivo App.Config fica fácil alterar e localizar a string de conexão.

Finalmente para poder acessar essa string de conexão a partir da sua aplicação você vai ter que usar a classe ConfigurationManager e essa classe esta no namespace System.Configuration.

Precisamos então incluir uma referência a System.Configuration no nosso projeto.

Clique no menu PROJECT e a seguir em Add Reference;

A seguir selecione o item System.Configuration e clique no botão OK;

Agora sim temos tudo pronto e ajustado e podemos partir para a nossa próxima tarefa que é criar uma camada de acesso a dados.

Criando a camada de acesso a dados (Data Access Layer - DAL)

O que é uma Camada de Acesso a Dados ?

É uma camada separada da camada da apresentação de dados que tem a função de efetuar a conexão com a fonte de dados e através de comandos SQL (neste nosso caso) obter os dados para apresentação. Esta separação facilita a manutenção e a portabilidade da aplicação.

A camada de apresentação, quando deseja exibir algum dado, chama a camada de acesso aos dados e solicita a informação.

A camada de apresentação não acessa dados nem a camada de dados faz apresentação. Cada uma cumpre o seu papel.

Uma  camada de acesso de dados deve fornecer os seguintes recursos:

  1. Conexão com a base de dados
  2. Abrir e Fechar as conexões
  3. Dar suporte as operações CRUD(Create,Read,Update e Delete)
  4. Realizar o gerenciamento de transações
  5. Possuir a independência do provedor
  6. Realizar o gerenciamento da concorrência

Para criar uma camada de acesso a dados podemos adotar duas abordagem :

  1. Criar um novo projeto do tipo Class Library e nele definir a camada de acesso a dados
  2. Criar uma classe que atuará como uma camada de acesso a dados

Na primeira abordagem temos a vantagem de poder gerar um DLL e distribuí-la sendo assim mais reutilizável. Vamos usar esta abordagem.

No menu FILE clique em Add -> New Project;

Selecione o template Windows -> Class Library e informe o nome DAL e clique no botão OK;

A seguir vamos renomear a classe Class1.vb, que foi criada com o projeto, com o nome AcessoDB.vb.

A seguir vamos definir o código abaixo nesta classe :

imports System.Data
Imports System.Data.OleDb
Imports System.Configuration
Imports DTO
Public Class AcessoDB

    Private Shared Function GetDbConnection() As OleDbConnection
        Try
            Dim conString As String = ConfigurationManager.ConnectionStrings("CadastroPacientesConnectionString").ConnectionString
            Dim connection As OleDbConnection = New OleDbConnection(conString)
            connection.Open()
            Return connection
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Private Shared Sub CloseConnection(conn As OleDbConnection)
        Try
            If conn.State = ConnectionState.Open Then
                conn.Close()
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub
    Public Shared Function ExecuteReader(ByVal sql As String) As IDataReader
        Dim reader As IDataReader = Nothing
        Using connection As OleDbConnection = GetDbConnection()
            Try
                Using command As New OleDbCommand(Sql, connection)
                    reader = command.ExecuteReader()
                End Using
            Catch ex As Exception
                Throw
            End Try
            Return reader
        End Using
    End Function

    Public Function ExecuteNonQuery(ByVal sql As String) As Integer
        Dim i As Integer = -1
        Using connection As OleDbConnection = GetDbConnection()
            Try
                Using command As New OleDbCommand(sql, connection)
                    i = command.ExecuteNonQuery()
                End Using
            Catch ex As Exception
                Throw
            End Try
            Return i
        End Using
    End Function

    Public Shared Function ExecuteDataSet(ByVal sql As String) As DataSet
        Dim ds As DataSet = Nothing
        Using connection As OleDbConnection = GetDbConnection()
            Try
                Using Command As New OleDbCommand(sql, connection)
                    ds = ExecuteDataSet()
                End Using
            Catch ex As Exception
                Throw
            End Try
            Return ds
        End Using
    End Function

    Public Shared Function ExecuteDataSet() As DataSet
        Dim da As OleDbDataAdapter = Nothing
        Dim cmd As IDbCommand = New OleDbCommand()
        Dim ds As DataSet = Nothing
        Try
            da = New OleDbDataAdapter()
            da.SelectCommand = CType(cmd, OleDbCommand)
            ds = New DataSet()
            da.Fill(ds)
        Catch ex As Exception
            Throw
        End Try
        Return ds
    End Function

    Public Overloads Shared Function GetDataTable(ByVal sql As String, ByVal parameterNames() As String, ByVal parameterVals() As String) As DataTable
        Using connection As OleDbConnection = GetDbConnection()
            Using da As OleDbDataAdapter = New OleDbDataAdapter(sql, connection)
                Dim table As New DataTable
                FillParameters(da.SelectCommand, parameterNames, parameterVals)
                da.Fill(table)
                Return table
            End Using
        End Using
    End Function

    Public Overloads Shared Function GetDataTable(ByVal sql As String) As DataTable
        Using connection As OleDbConnection = GetDbConnection()
            Using da As New OleDbDataAdapter(sql, connection)
                Dim table As New DataTable
                da.Fill(table)
                Return table
            End Using
        End Using
    End Function

    Public Shared Function SelectScalar(ByVal sql As String, ByVal parameterNames() As String, ByVal parameterVals() As String) As String
        Using connection As OleDbConnection = GetDbConnection()
            Using command As OleDbCommand = New OleDbCommand(sql, connection)
                FillParameters(command, parameterNames, parameterVals)
                Return CStr(command.ExecuteScalar)
            End Using
        End Using
    End Function

    Public Shared Function SelectScalar(ByVal sql As String) As String
        Using connection As OleDbConnection = GetDbConnection()
            Using command As New OleDbCommand(sql, connection)
                Return CStr(command.ExecuteScalar)
            End Using
        End Using
    End Function

    Public Shared Function CRUD(ByVal sql As String, ByVal parameterNames() As String, ByVal parameterVals() As String) As Integer
        Try
            Using connection As OleDbConnection = GetDbConnection()
                Using command As New OleDbCommand(sql, connection)
                    FillParameters(command, parameterNames, parameterVals)
                    Return command.ExecuteNonQuery()
                End Using
            End Using
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Private Shared Sub FillParameters(ByVal command As OleDbCommand, ByVal parameterNames As String(), ByVal parameterVals As String())
        Try
            If parameterNames IsNot Nothing Then
                For i = 0 To parameterNames.Length - 1
                    command.Parameters.AddWithValue(parameterNames(i), parameterVals(i))
                Next
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Sub
End Class

A classe AcessoDB possui diversos métodos estáticos declarados com o modificado Shared. Dessa forma não precisaremos criar uma instância da classe para acessar os métodos.

A seguir temos os métodos da classe AcessoDB :

  1. GetDbConnection
  2. CloseConnection
  3. ExecuteReader
  4. ExecuteNonQuery
  5. 2 métodos ExecuteDataSet
  6. 2 métodos GetDataTable
  7. 2 métodos SelectScalar
  8. CRUD
  9. FillParameters

É uma classe básica que contém os métodos para realizar as principais tarefas de acesso e manipulação de dados.

A criação da camada de acesso a dados nos leva a pensar em separação de responsabilidades, e, assim a camada de apresentação não deverá conter nada relacionado com o acesso a dados e isso inclui : objetos ADO .NET de acesso a dados, comandos SQL e stored procedures.

Então note que os métodos ExecuteReader(), ExecuteNonQuery(), ExecuteDataSet(), GetDataTable() e SelectScalar() devem receber como parâmetro um comando SQL e para não ter que declarar comandos SQL na camada de apresentação temos que criar outra camada chamada Camada de Negócio ou Businnes Logic Layer - BLL onde iremos realizar as validações referente ao nosso domínio.

Definindo a camada de negócios - BLL

É na camada de negócios que se localizam as regras do negócio e da validação dessas regras. (Existem validações feitas na camada de apresentação mas refere-se a validações de dados entrados pelo usuário apenas).

Então, com uma camada de negócios (BLL) podemos efetuar efetuar uma validação de regra de negócio e em seguida passar os objetos para a camada de apresentação.

No menu FILE clique em Add -> New Project;

Selecione o template Windows -> Class Library e informe o nome BLL e clique no botão OK;

A seguir vamos renomear a classe Class1.vb, que foi criada com o projeto, com o nome CustomerBLL.vb pois vamos acessar a tabela Customers.

Além disso vamos criar uma classe chamada Customer nesta camada que irá representar o nosso domínio. A classe Customer deverá possuir apenas as propriedades com os mesmos nomes definidos nos campos da tabela Customers

Clique no menu PROJECT e a seguir em Add Class e informe o nome Customer. A seguir defina o seguinte código nesta classe:

Observe que a classe Customers possui propriedades com o mesmo nome dos campos da tabela Customers.

Na nossa aplicação iremos obter as informações do cliente pelo seu código exibindo-as em um formulário nos demais controles TextBox.

O usuário informa o código do cliente e clica no botão procurar que acessa o banco de dados e procurar pelo código do cliente na tabela Customers. Se encontrar as informações serão exibidas nos demais controles:

Temos que ter isso em mente para definir o código da classe CustomerBLL. Assim teremos que ter um método que retorne um objeto do tipo Customer que foi definido na classe Customer.

Mas antes de definir o código da camada de negócios BLL observe que agora a nossa aplicação possui 3 camadas assim representadas:

Cada camada é um projeto diferente e o fluxo da informação deve ser feita na seguinte ordem:

A camada de apresentação solicita uma informação à camada de negócio que por sua vez a solicita à camada de acesso aos dados que acessa os dados e retorna o resultado para camada de negócio que retorna para a camada de apresentação.

A camada de apresentação não acessa diretamente a camada de acesso aos dados.

Então para que as camadas possam enxergar umas às outras temos que incluir referências nos projetos conforme mostrado a seguir:

1- Clique com o botão direito do mouse sobre o projeto  Cenario1_AcessoAdoNet e a seguir em Add -> Reference;

2- Agora clique com o botão direito do mouse sobre o projeto  BLL e a seguir em Add -> Reference;

Agora sim podemos definir os métodos na camada de negócios pois ela já esta acessando as classes da camada de acesso a dados.

Digite o código abaixo na classe CustomerBLL:

Imports DAL
Public Class CustomerBLL
    Public Function GetCustomerId(id As String) As Customer
        Try
            Dim sql As String = "SELECT CustomerID, CompanyName, ContactName, ContactTitle, Region, PostalCode, Country, Phone, Fax FROM Customers WHERE CustomerID = '" & id & "'"
            Dim tabela As New DataTable
            tabela = AcessoDB.GetDataTable(sql)
            Return GetCustomer(tabela)
        Catch ex As Exception
            Throw ex
        End Try
    End Function
    Public Function GetCustomer(ByVal tabela As DataTable) As Customer
        Try
            Dim _customer As New Customer
            If tabela.Rows.Count > 0 Then
                 _customer.CustomerID = tabela.Rows(0).Item(0)
                _customer.CompanyName = tabela.Rows(0).Item(1)
                _customer.ContactName = tabela.Rows(0).Item(2)
                _customer.ContactTitle = tabela.Rows(0).Item(3)
                _customer.Address = tabela.Rows(0).Item(4)
                _customer.City = tabela.Rows(0).Item(5)
                _customer.Region = IIf(IsDBNull(tabela.Rows(0).Item(6)), "Não Informado", tabela.Rows(0).Item(6))
                _customer.PostalCode = tabela.Rows(0).Item(7)
                _customer.Country = tabela.Rows(0).Item(8)
                _customer.Phone = tabela.Rows(0).Item(9)
                _customer.Fax = IIf(IsDBNull(tabela.Rows(0).Item(10)), "Não Informado", tabela.Rows(0).Item(10))
               Return _customer
            Else
                _customer = Nothing
                Return _customer
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Function
End Class

Observe que declaramos uma referência ao projeto DAL : Imports DAL

Nesta classe temos dois métodos:

  1. GetCustomerId()

Retorna um objeto do tipo Customer com base no código do cliente. Este método faz uma consulta SQL usando a cláusula Where e procura pelo cliente com o código informado usando o método GetDataTable() da camada DAL.

A seguir este método chama o método GetCustomer() passando o DataTable retornado.

  1. GetCustomer()

Este método recebe um datatable como parâmetro e retorna um objeto Customer obtido a partir da classe Customer.

Por enquanto é tudo o que precisamos. Vamos agora usar esses métodos na camada da apresentação.

Definindo a camada de apresentação

No formulário form1.vb vamos incluir os seguintes controles a partir da ToolBox:

Disponha os controles conforme o leiaute da figura abaixo:

Ao iniciar o projeto o formulário será apresentado e devemos incluir o código do cliente na caixa de texto Código e clicar no botão de comando btnLocalizar. Neste momento vamos chamar o método GetCustomerId() da camada BLL que deverá procurar pelo cliente na camada DAL e retornar os resultados preenchendo os controles do formulário.

Neste momento você deve estar pensando : "Tivemos todo esse trabalho para fazer somente isso ????"

Para fazer uma casa bem construída temos que primeiro fazer um alicerce sólido e foi isso que fizemos : criamos os fundamentos do nosso projeto de forma sólida e a partir de agora podemos desfrutar disso.

Veja como deve ficar o código do formulário associado ao evento Click do botão de comando btnLocalizar :

Imports BLL
Private Sub btnLocalizar_Click(sender As Object, e As EventArgs) Handles btnLocalizar.Click
        Try
            If String.IsNullOrEmpty(txtCodigo.Text) Then
                MessageBox.Show("Informe o código do cliente.", "Codigo", MessageBoxButtons.OK, MessageBoxIcon.Information)
                txtCodigo.Focus()
                Return
            Else
                Dim clientebll As New CustomerBLL
                Dim cliente As New Customer
                cliente = clientebll.GetCustomerId(txtCodigo.Text)
                If Not IsNothing(cliente.CustomerID) Then
                    txtNomeEmpresa.Text = cliente.CompanyName
                    txtNomeContato.Text = cliente.ContactName
                    txtTitulo.Text = cliente.ContactTitle
                    txtEndereco.Text = cliente.Address
                    txtCidade.Text = cliente.City
                    txtRegiao.Text = cliente.Region
                    txtCodigoPostal.Text = cliente.PostalCode
                    txtPais.Text = cliente.Country
                    txtTelefone.Text = cliente.Phone
                    txtFax.Text = cliente.Fax
                Else
                    MessageBox.Show("Cliente não localizado", "Não localizado", MessageBoxButtons.OK, MessageBoxIcon.Information)
                End If
            End If
        Catch ex As Exception
            MessageBox.Show("Erro ao acessar o cliente", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

Executando o projeto e informando um código de cliente podemos ter as situações mostradas a seguir:

a-) O código é localizado e dos dados do cliente são exibidos nos demais controles de formulário;
b-) O cliente não é localizado na base de dados;

Neste primeiro cenário tivemos todo o trabalho para criar os fundamentos da aplicação. Criamos as camadas, definimos os métodos e as referências e agora podemos usar a estrutura criada para realizar as demais tarefas.

Aguarde a continuação do artigo onde irei mostrar como retornar uma lista de clientes e preencher controles de lista.

Pegue o projeto completo aqui: Cenario1_AccessAdoNet.zip

 

Veja também a vídeo aula relacionada em : VB .NET - Preenchendo um Combobox e um ListBox com dados relacionados

  • João 6:35 Declarou-lhes Jesus. Eu sou o pão da vida; aquele que vem a mim, de modo algum terá fome, e quem crê em mim jamais terá sede.

  • Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

    Quer migrar para o VB .NET ?

    Quer aprender C# ??

    Quer aprender os conceitos da Programação Orientada a objetos ?

     

     

                 Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter
     

    Referências:


    José Carlos Macoratti