Seções iMasters
.NET + Banco de Dados + Desenvolvimento + PostgreSQL

ASP .NET – Acessando PostGreSQL em camadas e com padrões de projeto – Parte 01

Este artigo vai mostrar como criar uma aplicação em
camadas com camada de negócios, interface e camada de acesso a dados para acessar
um banco de dados PostgreSQL usando as boas práticas.

Em meu artigo ASP .NET – Conexão com o
PostGreSQL
, eu mostrei como acessar e exibir os dados de uma tabela do PostGreSQL usando o modo
mais prático, mas não o mais recomendado.

Como eu já
mostrei o que você precisa fazer para poder realizar a conexão com o PostGreSQL,
não vou repetir tudo novamente. Vou focar na construção de uma aplicação
usando as boas práticas e padrões de projeto com ADO  .NET.

Para este
artigo, eu criei uma tabela chamada alunos no PostGreSQL com a seguinte
estrutura usando pgAdmin:

Nessa tabela, temos que o campo alunoid é do
tipo serial, ou seja, é equivalente ao campo autonumeração. A chave
primária da tabela também é o campo alunoid.

Nosso objetivo inicial será acessar os dados desta tabela
alunos e exibi-los em um
controle GridView em uma página ASP .NET.

Parece bem simples, mas vamos mostrar como fazer isso criando uma aplicação
onde iremos separar a interface da camada de acesso a dados e criarmos também uma
camada de negócio e de entidades. Acompanhe…

Mesmo para aplicações simples, eu recomendo que você sempre utilize as boas
práticas, e a separação da camada de interface do acesso aos dados é uma delas.

Antes de iniciar, quero deixar claro que esta não é a única forma de você criar uma aplicação em camadas; você pode simplificar ou refinar o exemplo mostrado neste artigo de acordo com suas necessidades. Eu já publiquei diversos artigos sobre esse assunto e se você compará-los verá que, mesmo o assunto sendo o mesmo,  ele é tratado de forma um pouco diferente em cada artigo, isso para que você veja as opções disponíveis e possa incorporar a que melhor se ajusta ao seu caso.

Vou começar desenhando o cenário:

Nosso banco de dados PostGreSQL está instalado em um servidor web e precisamos acessar a tabela alunos e exibir os seus dados em uma página ASP .NET usando um controle GridView.

Temos, então, que criar uma aplicação ASP .NET, que neste artigo irá usar WebForms, mas poderíamos usar MVC também.

Criando a solução e os projetos

Abra o VS 2008 e, no menu File, selecione New Project.

A seguir, selecione a linguagem Visual C# (poderíamos fazer em VB .NET, mas vou variar um pouco) e, em Templates, selecione ASP .NET Web Application, informando o nome EscolaWeb e clicando em OK.

Será criado um projeto Web chamado EscolaWeb, contendo a página Default.aspx , o arquivo web.config, a pasta App_Data e as pastas Properties e References.

Esse seria o caminho padrão para conseguir o nosso objetivo, bastava agora colocar o controle na página Default.aspx e no code-behind inserir o código para realizar o acesso ao banco de dados, obter os dados da tabela e exibir no controle GridView. Isso nós já fizemos no meu artigo citado no início.

Vamos criar uma aplicação mais robusta em camadas com a seguinte estrutura:

  • Camada de Entidades – Entidades – deverá possuir as classes que representam as entidades do nosso negócio. Para o nosso caso teremos, neste momento, a entidade Aluno que será representada pela classe Aluno.cs;
  • Camada de Negócios – CamadaNegocios – deverá conter as classes para definir as regras do negócio e validação dessas regras. Para este exemplo, essa camada servirá como uma ponte que irá acessar a camada de acesso a dados;
  • Camada de Acesso a dados – CamadaAcessoDados – deverá conter as classes responsáveis pelo acesso e persistência de dados no banco de dados;
  • Camada de Interface – EscolaWeb – Conterá as páginas ASP.NET para exibição e entrada de dados do usuário.

Deveremos ter, então, uma solução com 4 projetos, onde o primeiro projeto, EscolaWeb, já foi criado. Vamos criar os demais…

No menu File selecione Add e a seguir New Project.

Selecione Visual C# -> Windows e na janela Templates o modelo Class Library informando o nome Entidades e clicando em OK.

Repita o procedimento anterior e crie da mesma forma os projetos CamadaNegocios, CamadaAcessoDados.

Ao final, a nossa janela Solution Explorer deverá exibir uma solução com 4 projetos conforme a figura abaixo:

Definindo as referências entre os projetos

Após criar a estrutura da solução, temos que pensar como os projetos irão se relacionar entre si. Estamos criando camadas em projetos distintos, de forma a separar as responsabilidades de cada camada e, dessa forma, a camada de apresentação não deverá saber nada da camada de acesso a dados. Com isso em mente, teremos a seguinte hierarquia de relacionamento entre os projetos:

EscolaWeb  =>   CamadaNegocios   =>  CamadaAcessoDados =>  Entidades
                                      Entidades                     Entidades

Ou seja:

  • A camada de interface EscolaWeb deverá ter uma referência a CamadaNegocios e Entidades;
  • A camada de negócios CamadaNegocios deverá ter uma referência para CamadaAcessoDados e Entidades;
  • A camada de acesso a dados CamadaAcessoDados deverá ter uma referência a Entidades.

Isso pode ser visto  clicando com o botão direito do mouse na Solução e selecionando o item Project Dependencies:  

Observe que a camada (projeto) Entidades deverá ser referenciado nos demais projetos.

A seguir, veremos como definir estas referências entre os projetos.

  • Selecione o projeto EscolaWeb e clique com o botão direito do mouse selecionando a opção Add Reference;
  • Na janela Add Reference, abra a aba Projects e selecione os projetos que deseja como referência para esse projeto e clique em OK.

Repita este procedimento para referenciar os demais projetos conforme indicado.

Com a estrutura da solução pronta, e as referências definidas, podemos iniciar a fase de codificação, e vamos começar pelo projeto Entidades. Nesse projeto, teremos a classe que representa a entidade Aluno, que fisicamente existe como uma tabela do banco de dados chamada alunos.

Definindo o código da camada Entidades

Abra o projeto Entidades e renomeie a classe Class1.cs criada por padrão para Aluno.cs e defina esse arquivo o seguinte código:

using System;
using System.Collections.Generic;
using System.Text;
namespace Macoratti.Entidades
{
public class Aluno
{
public Aluno() { }
public int Alunoid { get; set; }
public int Turmaid { get; set; }
public string Apelido { get; set; }
public string Nome { get; set; }
public string Email { get; set; }
public char Sexo { get; set; }
public Aluno(int alunoid, int turmaid, string apelido, string nome, string email, char sexo)
{
this.Alunoid = alunoid;
this.Turmaid = turmaid;
this.Apelido = apelido;
this.Nome = nome;
this.Email = email;
this.Sexo = sexo;
}
}
}

A classe Aluno define os membros representando cada campo da tabela alunos e também um construtor vazio e outro onde definimos os valores para cada membro.

Essa classe servirá como um transporte de dados (DTO-Data Transfer Objects) entre as camadas, pois, como veremos mais à frente, iremos trabalhar com o objeto Aluno para obter informações da tabela do banco de dados.

Lembrando que para cada entidade de negócio teremos uma classe que a represente e, no momento, temos somente a tabela alunos e a entidade Aluno.

Definindo o código da camada de Acesso a dados

Na camada de acesso a dados, devemos ter as classes que realizam o acesso e a persistência dos dados. A nossa camada de acesso a dados deverá ter a seguinte estrutura:

  • Interface – IAcessoDadosObject – contendo as assinaturas dos métodos para realizar as operações CRUD no banco de dados;
  • A classe DALHelper – contendo os métodos para acessar e persistir dados usando datareaders, datasets, e os recursos da ADO .NET;
  • A classe AlunoDAL – que deverá herdar da interface IAcessoDadosObject – e que deverá implementar os métodos definidos na interface.

Clique com o botão direito do mouse sobre o projeto CamadaAcessoDados e selecione Add -> Class e informe o nome IAcessoDadosObject.cs e clique em OK.

A seguir, defina o seguinte código na interface criada:

using System;
using System.Collections.Generic;
namespace Macoratti.DAL
{
public interface IAcessoDadosObject <T> where T : new()
{
T Get<K>(K id);
List<T> GetTop();
void Insert(T obj);
void Update<K>(K id, T obj);
void Delete<K>(K id);
}
}

Essa interface define a assinatura dos métodos para obter e atualizar informações na tabela alunos usando Generics. Observe que estamos tipando a interface de forma genérica e os métodos serão usados pelas demais classes.

Temos um contrato para definir os métodos:

  • T Get<K>(K id); -> retorna um único aluno pelo id informado;
  • List<T> GetTop(); – retorna uma lista de alunos;
  • void Insert(T obj); – inclui um aluno;
  • void Update<K>(K id, T obj); atualiza um aluno;
  • void Delete<K>(K id); exclui um aluno.

A classe DALHelper poderá conter os métodos que você achar necessário para acessar tabelas e banco de dados e tratar conexões.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using Npgsql;

namespace Macoratti.DAL
{
public class DALHelper
{
string server = "localhost";
string port = "5432";
string database = "macoratti";
string userId = "macoratti";
string userPassword = "numsey";
public NpgsqlConnection conexaoBD { get; set; }
public string stringConexaoBD { get; set; }
public DALHelper()
{
this.stringConexaoBD = string.Format("Server={0};Port={1};Database={2};User Id={3};Password={4};",
server, port, database, userId, userPassword);
this.conexaoBD = new NpgsqlConnection(this.stringConexaoBD);
}
public DALHelper(string stringConexaoBD)
{
this.conexaoBD = new NpgsqlConnection(this.stringConexaoBD);
}
public static DALHelper Create()
{
return new DALHelper();
}
public static DALHelper Create(string stringConexaoBD)
{
return new DALHelper(stringConexaoBD);
}
public void OpenConnection()
{
if (this.conexaoBD.State == System.Data.ConnectionState.Closed)
{
this.conexaoBD.Open();
}
}
public void CloseConection()
{
this.conexaoBD.Close();
}
public NpgsqlDataReader ExecuteDataReader(string sql)
{
NpgsqlDataReader dr = null;
try
{
if (this.conexaoBD.State == System.Data.ConnectionState.Closed)
{
this.conexaoBD.Open();
}
NpgsqlCommand cmd = new NpgsqlCommand(sql,this.conexaoBD);
dr = cmd.ExecuteReader();
return dr;
}
catch (Exception ex)
{
throw ex;
}
}
}
}
}

A classe DALHelper é uma classe que nos auxilia a realizar consultas e operações CRUD na base de dados. Ele possui a definição da variáveis usadas na conexão com o banco de dados e os métodos:

  • Construtores DALHelper – criam e retornam uma conexão com base em uma string de conexão padrão ou fornecida;
  • OpenConnection – abre uma conexão;
  • CloseConnection – fecha uma conexão;
  • ExecuteDataReader – retorna um datareader.

Observe que essa classe usa os namespaces System.Data e  NpgSql, que dá acesso as classes ADO .NET e ao conector Npgsql, que dá acesso às classes dos provedores para acesso ao banco de dados PostgreSql (Lembre-se que você tem que referenciar a library do conector Npgsql nesse projeto).

Falta definir a classe AlunosDAL, que deverá implementar os métodos definidos na interface. Essa classe deverá implementar a interface que foi definida.

Como para esse momento eu vou precisar somente acessar os dados da tabela, somente vou definir o código completo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Npgsql;
using Macoratti.Entidades;
namespace Macoratti.DAL
{
public class AlunoDAL : IAcessoDadosObject<Aluno>
{
private DALHelper dal = new DALHelper();
public Aluno Get<K>(K id)
{
throw new NotImplementedException();
}
public List<Aluno> GetTop()
{
List<Aluno> alunos = new List<Aluno>();
NpgsqlDataReader reader = null;
try
{
string query = "select * from alunos";
dal.OpenConnection();
reader = dal.ExecuteDataReader(query);
while (reader.Read())
{
Aluno aluno = new Aluno();
aluno.Turmaid = Convert.ToInt32(reader["turmaid"]);
aluno.Apelido = reader["apelido"].ToString();
aluno.Email = reader["email"].ToString();
aluno.Nome = reader["nome"].ToString();
aluno.Sexo = Convert.ToChar(reader["sexo"]);
alunos.Add(aluno);
}
reader.Close();
}
finally
{
if (reader != null)
{
reader.Close();
}
this.dal.CloseConection();
}
return alunos;
}
public void Insert(Aluno oAluno)
{
throw new NotImplementedException();
}
public void Update<K>(K id, Aluno oAluno)
{
throw new NotImplementedException();
}
public void Delete<K>(K id)
{
throw new NotImplementedException();
}
}
}

Nessa classe, temos a implementação dos métodos declarados na interface IAcessoDadosObject, sendo que a classe recebe o tipo Aluno e o método GetTop() retorna uma lista de objetos alunos.

Obs: Na verdade, o único método completamente implementado é o método ExecuteDataReader, os outros irei implementar conforme for precisando.

O método GetTop() utiliza uma chamada ao método ExecuteDataReader da classe DALHelper, passando como parâmetro a consulta SQL.

Na continuação deste artigo irei definir a camada de Negócios, onde estarei usando o padrão Factory e Facade para, em seguida, poder exibir os dados na camada de interface. Aguarde a continuação do artigo!

Eu sei é apenas, ASP .NET com boas práticas e padrões de projeto, mas eu gosto…

Comente também

2 Comentários

Excelente artigo, estava procurando artigos relacionados e esse está me ajudando e muito. Não vejo a hora de ler o próximo.

abraços.

Magno

Muito Bom!

Qual a sua opinião?