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:
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:
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:
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.