.NET

4 jul, 2014

ASP .NET – Criando um projeto em 3 Camadas – UI, BLL e DAL (revisão) – Parte 02

Publicidade

Na primeira parte deste artigo apresentei os conceitos sobre uma aplicação em três camadas e criei a solução definindo sua arquitetura e estrutura no Visual Studio Express 2012 for web.

Vamos continuar definindo as funcionalidades de cada camada iniciando pela camada de acesso a dados: DAL.

Recursos usados:

  • Visual Studio Express 2012 for Web;
  • SQL Server 2012 Local DB;
  • ASP .NET Web Forms 4.5.

Como o assunto do artigo já foi exaustivamente abordado em meu site, não vou me ater muito a certos detalhes. Dessa forma, tornarei o artigo o mais simples e objetivo possível para aqueles que estão tendo o seu primeiro contato com um projeto em três camadas.

Definindo as funcionalidades da DAL

A camada de acesso a dados é responsável pelo acesso e persistência de informações no banco de dados usado pela aplicação.

No nosso exemplo, vamos utilizar o SQL Server 2012 Local DB, onde teremos um banco de dados Cadastro.mdf e uma tabela Clientes com a seguinte estrutura:

aspn_3cam21

O banco de dados e a tabela podem ser criados no próprio ambiente do Visual Studio através da janela DataBase Explorer.

A string de conexão com o banco de dados para o nosso exemplo é definida como: “Data Source=(LocalDB)\v11.0;Initial Catalog=Cadastro;Integrated Security=True”.

E vamos armazená-la no arquivo de configuração da aplicação Web.Config criando uma seção <connectionString> conforme abaixo:

<?xml version="1.0"?>
<configuration>
    <system.web>
      <compilation debug="true" strict="false" explicit="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5"  />
    </system.web>
  <connectionStrings>
    <add name="conexaoClienteSQLServer" connectionString="Data Source=(LocalDB)\v11.0;Initial Catalog=Cadastro;Integrated Security=True"/>    
  </connectionStrings>
</configuration>

Note que identificamos a string de conexão pela tag <add name> com o nome : conexaoClienteSQLServer.

Para poder acessar e obter o valor da string de conexão no arquivo Web.Config temos que incluir uma referência ao namespace System.Configuration no projeto DAL.

Clique com o botão direito sobre o projeto DAL e selecione Add Reference;

Na janela Add Reference clique em Assemblies e selecione o item System.Configuration clicando no botão OK:

aspn_3cam22

Portanto, as ações para acessar, incluir, alterar e excluir dados deverá ser feita exclusivamente pela camada de acesso a dado a dados. Para isso vamos criar uma classe no projeto DAL chamada AcessoDB.vb.

Esta classe deverá ter somente referências a classes para acesso a dados e não deverá conter nenhuma referência a outras classes.

Digite o código abaixo no arquivo AcessoDB.vb:

Imports System.Data
Imports System.Data.SqlClient
Imports System.Configuration
Imports DTO
Public Class AcessoDB

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

    Public Shared Function ExecuteReader(ByVal sql As String) As IDataReader
        Dim reader As IDataReader = Nothing
        Using connection As SqlConnection = GetDbConnection()
            Try
                Using command As New SqlCommand(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 SqlConnection = GetDbConnection()
            Try
                Using command As New SqlCommand(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 SqlConnection = GetDbConnection()
            Try
                Using Command As New SqlCommand(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 SqlDataAdapter = Nothing
        Dim cmd As IDbCommand = New SqlCommand()
        Dim ds As DataSet = Nothing
        Try
            da = New SqlDataAdapter()
            da.SelectCommand = CType(cmd, SqlCommand)
            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 SqlConnection = GetDbConnection()
            Using da As SqlDataAdapter = New SqlDataAdapter(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 SqlConnection = GetDbConnection()
            Using da As New SqlDataAdapter(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 SqlConnection = GetDbConnection()
            Using command As SqlCommand = New SqlCommand(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 SqlConnection = GetDbConnection()
            Using command As New SqlCommand(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 SqlConnection = GetDbConnection()
                Using command As New SqlCommand(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 SqlCommand, 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 que acessam, retornam e persistem informações em um banco de dados SQL Server. É uma classe bem básica que usa os recursos da ADO .NET.

A maioria dos métodos usa o modificador Shared, indicando que o método é estático e que portanto não é um método de instância; dessa forma não precisamos criar uma instância da classe AcessoDB para ter acesso aos métodos, basta informar o nome da classe seguida de ponto e o nome do método: AcessoDB.GetDataTable().

Você pode criar uma DAL, que ao invés de retornar objetos DataTable, DataSet, DataReader etc, retorne objetos de negócio usando os recursos do Generics da plataforma .NET.

O conteúdo da classe que faz o papel da DAL pode variar dependendo do cenário de sua aplicação. Como a classe está em uma camada separada das demais, qualquer alteração feita nesta classe não deve alterar as classes das outras camadas. Essa classe será chamada e referenciada pela camada de negócios(BLL) para realizar quaisquer operações com o banco de dados.

Definindo as funcionalidades da camada de negócios – BLL

Na camada de negócios – BLL – iremos ter as classes que tratam as regras de negócio da aplicação. Vamos criar uma interface ICliente.vb, onde iremos definir os contratos que deverão ser implementados pela classe ClienteBLL – que será a classe que irá realizar o tratamento das regras de negócio da aplicação.

No menu PROJECT, clique em Add Class e selecione o template Interface, informando o nome ICliente.vb e clicando no botão Add:

aspn_3cam23

Uma interface, no paradigma da orientação a objetos, é  um tipo de classe que contém apenas as assinaturas de métodos, propriedades, eventos e indexadores.

A implementação dos membros é feita por uma classe concreta ou struct que implementa a interface. O nome de uma interface geralmente possui a primeira letra I maiúscula, seguido do nome da interface. No nosso caso : ICliente.

Digite o código a seguir na interface ICliente:

Imports DTO
Public Interface ICliente(Of T)

    Function ExibirTodos() As DataTable
    Function Exibir() As List(Of T)
    Sub Incluir(ByVal obj As T)
    Sub Alterar(ByVal obj As T)
    Sub Excluir(ByVal obj As T)
    Function Consultar(ByVal nome As String) As DataTable
    Function GetClienteId(ByVal id As Integer) As Cliente

End Interface

Nesta interface temos a referência ao namespace DTO onde definimos a classe Cliente. A interface declara o métodos contendo apenas a assinatura que deverá ser implementada por uma classe concreta.

Nossa interface é uma lista genérica do tipo T, onde T representa uma classe que nosso exemplo será a classe Cliente. O método Exibir() retorna uma lista genérica do tipo T, o método GetClienteId() retorna um tipo Cliente e os métodos Incluir(), Alterar() e Excluir() recebem como argumento um objeto do tipo T.

Para implementar essa interface vamos criar a classe ClienteBLL via menu PROJECT, clicando em Add Class e selecionando o template Class.

Na linguagem VB .NET, a sintaxe usada para indicar a utilização de uma interface usa a palavra chave Implements após o nome da classe concreta, que vai implementar a interface seguido do nome dela.

Abaixo temos o código da classe concreta ClienteBLL que implementa a interface ICliente:

Imports DAL
Imports DTO
Public Class ClienteBLL
    Implements ICliente(Of Cliente)
    Public Function GetClienteId(id As Integer) As Cliente Implements ICliente(Of Cliente).GetClienteId
        Try
            Dim sql As String = "SELECT Id,Nome,Endereco,Telefone,Email,Observacao FROM Clientes WHERE Id = " & id
            Dim tabela As New DataTable
            tabela = AcessoDB.GetDataTable(sql)
            Return GetCliente(tabela)
        Catch ex As Exception
            Throw ex
        End Try
    End Function
    Public Function GetCliente(ByVal tabela As DataTable) As Cliente
        Try
            Dim _Cliente As New Cliente
            If tabela.Rows.Count > 0 Then
                _Cliente.Id = tabela.Rows(0).Item(0)
                _Cliente.nome = tabela.Rows(0).Item(1)
                _Cliente.endereco = tabela.Rows(0).Item(2)
                _Cliente.telefone = tabela.Rows(0).Item(3)
                _Cliente.email = tabela.Rows(0).Item(4)
                _Cliente.observacao = tabela.Rows(0).Item(5)
                Return _Cliente
            Else
                _Cliente = Nothing
                Return _Cliente
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Public Function Exibir() As List(Of Cliente) Implements ICliente(Of Cliente).Exibir
        Try
            Dim sql As String = "SELECT * FROM Clientes"
            Dim tabela As New DataTable
            tabela = AcessoDB.GetDataTable(sql)
            Return GetListaCliente(tabela)
        Catch ex As Exception
            Throw ex
        End Try
    End Function
    Public Function GetListaCliente(ByVal tabela As DataTable) As List(Of Cliente)
        Try
            Dim listaCliente As New List(Of Cliente)
            Dim i As Integer = 0
            Dim registros = tabela.Rows.Count
            If registros > 0 Then
                For Each drRow As DataRow In tabela.Rows
                    Dim _Cliente As New Cliente
                    _Cliente.Id = tabela.Rows(i).Item(0)
                    _Cliente.nome = tabela.Rows(i).Item(1)
                    _Cliente.endereco = tabela.Rows(i).Item(2)
                    _Cliente.telefone = tabela.Rows(i).Item(3)
                    _Cliente.email = tabela.Rows(i).Item(4)
                    _Cliente.observacao = tabela.Rows(i).Item(5)
                    listaCliente.Add(_Cliente)
                Next
                While i <= registros
                    Dim _Cliente As New Cliente
                    _Cliente.Id = tabela.Rows(i).Item(0)
                    _Cliente.nome = tabela.Rows(i).Item(1)
                    _Cliente.endereco = tabela.Rows(i).Item(2)
                    _Cliente.telefone = tabela.Rows(i).Item(3)
                    _Cliente.email = tabela.Rows(i).Item(4)
                    _Cliente.observacao = tabela.Rows(i).Item(5)
                    listaCliente.Add(_Cliente)
                    i += i
                End While
                Return listaCliente
            Else
                listaCliente = Nothing
                Return listaCliente
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Function
    Public Function ConsultarPorID(id As Integer) As DataTable Implements ICliente(Of Cliente).ConsultarPorID
        Dim sql As String = "SELECT Id,Nome,Endereco,Telefone,Email,Observacao FROM Cliente WHERE Id = " & id
        Try
            Return AcessoDB.GetDataTable(sql)
        Catch ex As Exception
            Throw ex
        End Try
    End Function
    Public Function Consultar(nome As String) As DataTable Implements ICliente(Of Cliente).Consultar
        Dim sql As String = "SELECT Id,Nome FROM Cliente WHERE Nome LIKE '" & nome & "%'" & " ORDER BY Nome"
        Try
            Return AcessoDB.GetDataTable(sql)
        Catch ex As Exception
            Throw ex
        End Try
    End Function
    Public Sub Incluir(oCliente As Cliente) Implements ICliente(Of Cliente).Incluir
        Dim sql As String = ""
        Try
            Dim parametrosNomes(5) As String
            parametrosNomes(0) = "@Nome"
            parametrosNomes(1) = "@Endereco"
            parametrosNomes(2) = "@Telefone"
            parametrosNomes(3) = "@Email"
            parametrosNomes(4) = "@Observacao"
            Dim parametrosValores(5) As String
            parametrosValores(0) = oCliente.nome
            parametrosValores(1) = oCliente.endereco
            parametrosValores(2) = oCliente.telefone '
            parametrosValores(3) = oCliente.email
            parametrosValores(4) = oCliente.observacao
            sql = "INSERT INTO Cliente(Nome,Endereco,Telefone,Email,Observacao) values (@Nome,@Endereco,@Telefone,@Email,@Observacao)"
            AcessoDB.CRUD(sql, parametrosNomes, parametrosValores)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Public Sub Alterar(oCliente As Cliente) Implements ICliente(Of Cliente).Alterar
        Dim sql As String = ""
        Try
            Dim parametrosNomes(6) As String
            parametrosNomes(0) = "@Id"
            parametrosNomes(1) = "@Nome"
            parametrosNomes(2) = "@Endereco"
            parametrosNomes(3) = "@Telefone"
            parametrosNomes(4) = "@Email"
            parametrosNomes(5) = "@Observacao"
            Dim parametrosValores(6) As String
            parametrosValores(0) = oCliente.Id
            parametrosValores(1) = oCliente.nome
            parametrosValores(2) = oCliente.endereco
            parametrosValores(3) = oCliente.telefone '
            parametrosValores(4) = oCliente.email
            parametrosValores(5) = oCliente.observacao
            sql = "UPDATE Cliente SET Nome=@Nome, Endereco=@Endereco ,Telefone=@Telefone,Email=@Email , Observacao=@Observacao Where Id=@Id"
            AcessoDB.CRUD(sql, parametrosNomes, parametrosValores)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub
    Public Sub Excluir(oCliente As Cliente) Implements ICliente(Of Cliente).Excluir
        Dim sql As String = ""
        Try
            Dim parametrosNomes(0) As String
            parametrosNomes(0) = "@Id"
            Dim parametrosValores(0) As String
            parametrosValores(0) = oCliente.Id
            sql = "DELETE FROM Cliente Where Id=@Id"
            AcessoDB.CRUD(sql, parametrosNomes, parametrosValores)
        Catch ex As Exception
            Throw ex
        End Try
    End Sub
   
    Public Function ExibirTodos() As DataTable Implements ICliente(Of Cliente).ExibirTodos
        Dim sql As String = "SELECT * FROM Clientes"
        Try
            Return AcessoDB.GetDataTable(sql)
        Catch ex As Exception
            Throw ex
        End Try
    End Function
End Class

Note que os métodos usam a classe AcessoDB seguida do nome do método desejado.

Eu estou usando instruções SQL no formato texto, definindo a instrução em uma variável. Outra opção seria utilizar stored procedures, o que teria algumas vantagens.

Agora podemos definir as funcionalidades da camada de apresentação – UI – que irá usar os recursos das demais camadas.

É isso que faremos na última parte do artigo.