ASP .NET - Acessando PostGreSQL em Camadas e com padrões de projeto I


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 de forma simples e prática 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:

 Nesta 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 é um delas.

Para o exemplo deste artigo eu estou usando o Visual Studio 2008 , o banco de dados PostgreSQL 8.3 e o conector .NET para PosgreSQL - Npgsql - .Net Data Provider for Postgresql que você instalar e referência no projeto específico.

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 este 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 esta 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;

Este 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 do arquivo.

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

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

No menu File selecione Add e a seguir New Project;

Selecione Visuaç 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 desta forma 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:

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 referência para este projeto e clique em OK;

Repita este procedimento para referenciar os demais projetos conforme indicado.

Com estrutura da solução pronta e as referências definidas podemos iniciar a fase de codificação e vamos começar pelo projeto Entidades. Neste 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 este 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.

Esta classe servirá como um transporte de dados (DTO-Data Transfer Objects) entre as camadas pois como veremos mais a 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:

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);
    }
}

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

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(Create,Update,Delete) 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 :

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

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

Como para este 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();
        }
    }
}

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

Veja a continuação do artigo em:  ASP .NET - Acessando PostGreSQL em Camadas e com padrões de projeto II

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

Referências:

José Carlos Macoratti