VB .NET - Acesso e Navegação de dados para novatos II


Na primeira parte deste artigo criamos uma camada para acessar os dados e definimos a interface.

Agora ficamos com a questão : É correto acessar a camada de acesso a dados diretamente da camada de inteface ?

Depende.

Se formos pensar em termos de separação de responsabilidades e desacoplamento a resposta é Não.

Mas porquê ?

Bem, suponha que eu queira acessar o método GetDados que esta definido na classe SQLHelper na camada de acesso dados -  DAL e preencher o controle DataGridView no formulário da camada de apresentação. Como eu faria isso ?

Eu teria que incluir uma referência no projeto Windows Forms para a camada de acesso a dados - DAL.

Depois teríamos que definir a declaração a do namespace DAL no formulário e no evento Load criar uma instância da classe SQLHelper e chamar o método GetDados passando uma string com o comando SQL para selecionar todos os registros. Abaixo vemos um exemplo de código usado para realizar essa tarefa:

Imports DAL

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim _dal As New SQLHelper
        dgvClientes.DataSource = _dal.GetDados("
Select * from Clientes")
    End Sub

Se olharmos com cuidados vamos encontrar alguns problemas nesta abordagem.

  1. Estamos definindo um comando SQL na camada de apresentação e assim qualquer alteração no banco de dados ou comando SQL implicará em termos que alterar a camada de apresentação;
  2. A camada de apresentação passou a ser responsável por definir um comando SQL e não mais em apenas a apresentar os resultados;
  3. Estamos acoplando diretamente a camada de apresentação à camada de acesso aos dados e isso não é bom pois a camada de apresentação nunca deve referenciar a camada de acesso a dados diretamente;

Como podemos resolver esses problemas ?

Simples, criando uma camada intermediária, uma camada de negócios - BLL (Business Logic Layer) - que atuará entre a camada de apresentação e a camada de acesso aos dados.

Então vamos fazer isso...

No menu FILE clique em Add -> New Project e selecione o template Class Library e informe o nome BLL.

Essa camada será responsável por receber as requisições da camada de apresentação, fazer as validações, definir as regras de negócio e retornar o resultado para a camada de apresentação.

É a camada BLL que vai acessar diretamente a camada de acesso aos dados - DAL.

Para isso temos que incluir uma referência à camada DAL no projeto BLL.

Clique com o botão direito do mouse sobre o projeto BLL e a seguir em Add Reference.

Na janela Reference Manager marque a opção DAL e clique em OK;

A seguir vamos renomear a classe Class1.vb criada com o projeto para ClienteBLL.vb essa classe deverá conter todos os métodos necessários para atender a demanda da camada de apresentação para acessar as informações dos clientes na camada de acesso a dados.

Vamos definir então o código abaixo na classe ClienteBLL :

Imports DAL
Imports System.Data

Public Class ClienteBLL

    Public _dal As SQLHelper
    Private dt As New DataTable

    Public Sub New()
        _dal = New SQLHelper
    End Sub

    Public Function getDadosClientes() As DataTable
        Try
            Dim sql As String = "Select * from Clientes"         
            dt = _dal.GetDados(sql)
            Return dt
        Catch ex As Exception
            Throw ex
        End Try
    End Function

End Class

Vamos entender o que fizemos nesta classe:

Declaramos os namespaces:

Imports DAL
Imports System.Data

O primeiro é necessário para acessarmos a camada DAL e o segundo por que vamos usar as classes da ADO .NET.

Definimos uma instância da classe SQLHelper e criamos uma instância de um objeto DataTable:

Public _dal As SQLHelper
Private dt As New DataTable

Precisamos da instância da classe para acessarmos os métodos nela definidos e do DataTable para receber o retorno do método GetDados()

A seguir no construtor da classe criamos uma nova instância da classe SQLHelper:

Public Sub New()
_dal = New SQLHelper
End Sub

Finalmente criamos o método getDadosClientes() que será chamado pela camada de interface. Este método retorna um objeto DataTable, defina a instrução SQL e chama o método GetDados() da camada DAL.

Public Function getDadosClientes() As DataTable
Try
Dim sql As String = "Select * from Clientes"         
dt = _dal.GetDados(sql)
Return dt
Catch ex As Exception
Throw ex
End Try
End Function

Assim a camada BLL esta pronta para ser usada pela camada de apresentação.

Na camada de apresentação vamos ter que incluir uma referência para a camada de negócios BLL.

Clique com o botão direito do mouse sobre o projeto AcessoDadosVBNET e a seguir em Add Reference.

Na janela Reference Manager marque a opção BLL e clique em OK;

Agora no formulário Form1.vb podemos definir o código abaixo para acessar a camada de negócio BLL, chamar o método getDadosClientes() e assim preencher o DataGridView:

Imports BLL

Public Class Form1

    Private _bll As New ClienteBLL

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        dgvClientes.DataSource = _bll.getDadosClientes()
    End Sub

End Class

Note que agora não temos mais nenhuma referência à camada de acesso a dados DAL, nem precisamos definir nenhuma instrução SQL quem faz isso é a camada de negócios.

A seguir vemos o resultado da execução do projeto:

Realizando a navegação

Agora temos que implementar a navegação pelos registros permitindo que o usuário acesse e exibe as informações de cada registro nos controles TextBox.

Podemos fazer isso definindo em cada evento Click dos botões de comandos chamadas para métodos que deverão ser criados na camada BLL, lembre-se que essa camada existe para atender a camada de apresentação.

Na camada BLL temos o método GetDados() que retorna um datatable e podemos usar esse objeto para realizar a navegação.

Para fazer isso vamos ter que criar uma classe Cliente na camada de negócios. Então no menu PROJECT clique em Add Class, informe o nome Cliente.vb e a seguir defina o código abaixo nesta classe:

Public Class Cliente

    Public Property ID As Integer
    Public Property Nome As String
    Public Property Email As String

End Class

Agora vamos definir os métodos que usará o datatable preenchido com as informações da tabela Clientes. Vamos precisar de 4 métodos:

  1. getPrimeiro
  2. getProximo
  3. getAnterior
  4. getUltimo

Abaixo vemos o código de cada método criado na classe ClienteBLL:

  Private Shared i As Integer = 0

  Public Function getPrimeiro() As Cliente
        Try
            Dim cli As New Cliente
            If dt.Rows.Count > 0 Then
                i = 0
                cli.ID = dt.Rows(i)("ID").ToString
                cli.Nome = dt.Rows(i)("Nome").ToString
                cli.Email = dt.Rows(i)("Email").ToString
            End If
            Return cli
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Function getProximo() As Cliente
        Try
            Dim cli As New Cliente
            If i < dt.Rows.Count - 1 Then
                i = i + 1
                cli.ID = dt.Rows(i)("ID").ToString
                cli.Nome = dt.Rows(i)("Nome").ToString
                cli.Email = dt.Rows(i)("Email").ToString
            End If
            Return cli
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Function getAnterior() As Cliente
        Try
            Dim cli As New Cliente
            If i = dt.Rows.Count - 1 Or i <> 0 Then
                i = i - 1
                cli.ID = dt.Rows(i)("ID").ToString
                cli.Nome = dt.Rows(i)("Nome").ToString
                cli.Email = dt.Rows(i)("Email").ToString
            End If
            Return cli
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Function getUltimo() As Cliente
        Try
            Dim cli As New Cliente
            i = dt.Rows.Count - 1
            cli.ID = dt.Rows(i)("ID").ToString
            cli.Nome = dt.Rows(i)("Nome").ToString
            cli.Email = dt.Rows(i)("Email").ToString
            Return cli
        Catch ex As Exception
            Throw ex
        End Try
    End Function

Observe que cada método retorna um objeto Cliente, e que esse objeto é preenchido com os dados do registro atual conforme a navegação for sendo realizada.

Estamos usando o objeto DataTable obtido no método GetDados() e conforme a opção chamada na camada de apresentação verificando a posição do registro na propriedade Rows do objeto DataTable.

A propriedade Rows obtém a coleção de linhas que pertencem à tabela. E para retornar a posição atual da linha que desejamos exibir definimos uma variável i que é o índice da linha atual.

Agora na camada de apresentação basta em cada evento Click chamar o método correspondente ao botão clicado. Veja como ficou o código:

 Private Sub btnPrimeiro_Click(sender As Object, e As EventArgs) Handles btnPrimeiro.Click

        Try
            carregaDados(_bll.getPrimeiro())
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub

    Private Sub btnProximo_Click(sender As Object, e As EventArgs) Handles btnProximo.Click
        Try
            carregaDados(_bll.getProximo())
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub

    Private Sub btnAnterior_Click(sender As Object, e As EventArgs) Handles btnAnterior.Click
        Try
            carregaDados(_bll.getAnterior())
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub

    Private Sub btnUltimo_Click(sender As Object, e As EventArgs) Handles btnUltimo.Click
        Try
            carregaDados(_bll.getUltimo)
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub

A rotina carregaDados() esta sendo usada para exibir os valores nas caixas de texto recebendo um objeto Cliente com a linha atual a ser exibida:

Private Sub carregaDados(ByVal Cliente As Cliente)
        txtID.Text = Cliente.ID
        txtEmail.Text = Cliente.Email
        txtNome.Text = Cliente.Nome
    End Sub

A seguir a figura que mostra a navegação:

Percebeu que a camada de apresentação ficou com pouco código e sem nenhuma referência à camada de acesso aos dados.

Temos assim um projeto com 3 camadas onde cada camada esta com sua responsabilidade bem definida. Isso vai facilitar a manutenção do sistema.

É um projeto bem simples mas que permitiu aplicarmos os conceitos básicos da programação orientada a objetos (alguns conceitos) e de boas práticas de programação.

Ao desenvolver o seu próximo projeto pense nisso e procure se acostumar a aplicar esses conceitos que a princípio podem parecer complexos mas que com alguma prática serão incorporados ao seu dia a dia.

Nota: Poderíamos ter retornado uma lista de objetos Clientes ao invés de um DataTable.

Para fazer isso temos que criar um método getListaClientes() que retorna uma lista
de objetos Clientes na camada BLL:

Public Function getListaClientes() As List(Of Cliente)

        Dim listaClientes As New List(Of Cliente)
        Dim dr As SqlDataReader

        Try
            Dim sql As String = "Select * from Clientes"
            dr = _dal.ExecuteDataReader(sql)

            While (dr.Read)
                Dim cli As New Cliente
                cli.ID = dr.GetInt32(0)
                cli.Nome = dr.GetString(1)
                cli.Email = dr.GetString(2)
                listaClientes.Add(cli)
            End While
            Return listaClientes

        Catch ex As Exception
            Throw ex
        End Try
    End Function

E na camada DAL um método ExecuteDataReader() que retorna um SqlDataReader:

Public Function ExecuteDataReader(sql As String) As SqlDataReader
        Dim dr As SqlDataReader = Nothing
        Try
            If Me.conexao.State = ConnectionState.Closed Then
                Me.conexao.Open()
            End If
            Dim cmd As New SqlCommand(sql, Me.conexao)
            dr = cmd.ExecuteReader()
            Return dr
        Catch ex As Exception
            Throw ex
        End Try
    End Function

Assim na camada de apresentação a chamada seria feita assim:

dgvClientes.DataSource = _bll.getListaClientes()


Pegue o projeto completo aqui:
AcessoDadosVBNET.zip

João 6:47 Em verdade, em verdade vos digo: Aquele que crê tem a vida eterna.

João 6:48 Eu sou o pão da vida.

Referências:


José Carlos Macoratti