Back-End

28 nov, 2014

C# – Login com Fluent NHibernate, NHibernate 4.0 e PostGreSql – Parte 01

Publicidade

Esta é a versão C# do mesmo artigo feito para o VB .NET que mostra como usar os Fluent NHibernate e NHibernate 4.0 para criar uma aplicação que realiza o login e faz o registro de um novo usuário no banco de dados PostgreSQL usando o padrão repository.

Na seção NHibernate do meu site você vai encontrar muitos artigos que eu já escrevi mostrando como usar os recursos do NHibernate.

Se você já chegou a usar o NHibernate e não conhece o Fluent NHibernate, deve saber que gerar os arquivos de mapeamento (.hbm) dá muito trabalho e que é uma tarefa que está sujeita a erros. Se isso era um quesito que o desmotivava a usar o NHibernate, fique sabendo que agora você não tem mais essa desculpa. O Fluent NHibernate chegou (há um bom tempo, por sinal) para auxiliar a realização dos mapeamentos das suas entidades com o seu banco de dados. Com ele podemos realizar o mapeamento via código sem ter que usar os arquivos .hbm.

Apenas para comparar, veja abaixo um exemplo de um arquivo de mapeamento .hbm gerado e sua contrapartida usando o Fluent NHibernate (fonte: https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started):

Arquivo XML .hbm:

<?xml version="1.0" encoding="utf-8" ?>  
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"  
  namespace="QuickStart" assembly="QuickStart">  
  <class name="Cat" table="Cat">  
    <id name="Id">  
      <generator class="identity" />  
    </id>  
    <property name="Name">  
      <column name="Name" length="16" not-null="true" />  
    </property>  
    <property name="Sex" />  
    <many-to-one name="Mate" />  
    <bag name="Kittens">  
      <key column="mother_id" />  
      <one-to-many class="Cat" />  
    </bag>  
  </class>  
</hibernate-mapping>

Código Fluent NHibernate equivalente:

public class CatMap : ClassMap<Cat>
{
  public CatMap()
  {
    Id(x => x.Id);
    Map(x => x.Name)
      .Length(16)
      .Not.Nullable();
    Map(x => x.Sex);
    References(x => x.Mate);
    HasMany(x => x.Kittens);
  }
}

O Fluent NHibernate pode ser baixado neste link.

Neste artigo eu vou criar um projeto Windows Forms usando a linguagem VB.NET e usando o NHibernate e Fluent NHibernate para criar um formulário de login e registro de usuários para acessar um banco de dados PostgreSQL.

Recursos usados:

Objetivos:

  • Usar os recursos do NHibernate e Fluent NHibernate e criar um formulário de Login em uma aplicação Windows Forms para acessar o PostgreSQL

Aprendizado:

  • Criar uma aplicação Windows Forms usando a linguagem VB .NET
  • Criar um banco de dados e tabela no PostgreSQL
  • Criar um repositório para acesso a dados
  • Criar as entidades para realizar o mapeamento ORM
  • Realizar o mapeamento ORM usando o Fluent NHibernate
  • Realizar o CRUD no PostgreSQL usando o NHibernate

Criando o banco de dados e a tabela no PosgreSQL

Para criar o banco de dados e a tabela, vamos usar o pgAdmin III (deve ser compatível com a versão do PostgreSQL que você usar).

Quando você abrir o pgAdmin verá seguinte janela:

c_pgsql1 (1)

Na janela à esquerda temos as conexões com o servidor de banco de dados. Inicialmente temos uma conexão padrão.

Durante a instalação, o PostGreSQL já configurou o acesso ao nosso servidor local.

Clique duas vezes sobre o item PostGreSQL 9.3 (localhost:5432) para abrir a janela de conexão como servidor e informar a senha que você definiu durante a instalação para acessar o PostgreSQL.

Se você clicar no (+) da opção Databases, verá que já existe um banco de dados definido como Postgresql que foi criado automaticamente na instalação. Esse banco de dados não será utilizado e não pode ser excluído por se tratar de um banco utilizado para administração do Postgresql.

Vamos criar nosso banco de dados. Clique com o botão direito do rato em cima de Databases e escolha a opção New Database:

c_pgsql4 (1)

Na janela New DataBase informe o nome do banco de dados – Cadastro e defina o Owner como sendo o usuário postgres:

c_pgsql5 (1)

Agora vamos criar a nossa tabela usuarios que deverá possuir a seguinte estrutura:

Para isso faça o seguinte:

  1. Selecione o objeto Tables()
  2. Clique no menu SQL
  3. Na janela do editor SQL digite a instrução SQL Create Table conforme abaixo para criar a tabela usuários
create table usuarios(
                id serial not null primary key,
                nome varchar(100),
                login varchar(50),
                senha varchar(50),
                status char(1)
                )
  1. Clique no botão para executar a instrução e criar a tabela no banco de dados Cadastro.

c_lpgnh8 (1)

Concluindo esta etapa, você poderá ver a tabela usuários e as coluna criadas no Object Browser.

Se clicar com o botão direito sobre a tabela, verá um menu suspenso com diversas opções para gerenciar a tabela.

Clicando em View Data -> View Top 100 Rows será aberta a janela onde você poderá incluir e visualizar os dados na tabela conforme figura abaixo:

c_lpgnh8 (1)

Criando a solução no VS 2013 Express Edition for Windows Desktop

Abra o Visual Studio 2013 Express for Windows Desktop e clique em New Project. Selecione o template Visual Studio Solution e informe o nome ControleUsuarios e clique no botão OK.

c_lpgnh1 (1)

Criamos uma solução vazia onde iremos agora incluir os nossos projetos.

No menu FILE clique em Add -> New Project e, a seguir, selecione a linguagem C#, o template Class Library e informe o nome Repositorio e clique no botão OK.

c_lpgnh11

No menu FILE, clique em Add -> New Project. Selecione o template Windows Forms Application e informe o nome Usuários e clique no botão Add.

Temos agora uma solução contendo dois projetos:

c_lpgnh12

Incluindo as referências ao NHibernate, Fluent NHibernate e ao provedor Npgsql

Vamos agora criar 2 pastas no projeto Repositório.

Clique com o botão direito do mouse sobre o projeto e a seguir clique em Add -> New Folder e informe o nome Entidades.

Repita o procedimento acima e crie a pasta com o nome Mapeamento.

Vamos agora referenciar o NHibernate, o Fluent NHibernate e o provedor Npgsql para acessar o PostgreSQL usando o Nuget.

O papel do Nuget é justamente ser um gerenciador de bibliotecas de modo a garantir que todas as dll´s de um pacote estejam atualizadas com suas versões corretas, evitando erros de referência em seus projetos.

No menu TOOLS ,clique em Library Package Manager -> Manage Nuget Packages for Solution.

c_lpgnh4 (1)

Na janela – Manage Nuget Packages – digite NHibernate para localizar o pacote e, a seguir, clique no botão Install.

c_lpgnh5 (1)

Clique no botão OK para instalar o pacote nos projetos da solução.

Selecione a seguir o pacote FluentNHibernate e clique no botão Install, repetindo o procedimento feito:

c_lpgnh6 (1)

Retorne a janela – Manage Nuget Packages – e digite Npgsql para localizar o pacote e a seguir clique no botão Install.

c_lpgnh7 (1)

Ao final, teremos as referências ao NHibernate, Fluent NHibernate e ao provedor Npgsql instalados em nossa solução e estamos prontos para criar o Repositório, as entidades e o mapeamento ORM.

Criando as Entidades e o Mapeamento com Fluent NHibernate

Vamos começar definindo a entidade Usuário na pasta Entidades. Clique com o botão direito do mouse sobre a pasta Entidades e em seguida selecione Add -> Class.

Informe o nome Usuário e digite o código abaixo neste arquivo:

namespace Repositorio.Entidades
{
    public class Usuario
    {
        public virtual int Id { get; set; }
        public virtual string Nome { get; set; }
        public virtual string Login { get; set; }
        public virtual string Senha { get; set; }
        public virtual char Status { get; set; }
    }
}

E importante usar o modificador Overridable na definição das propriedades e atentar que cada uma deve estar relacionada com as colunas da tabela usuários, criada no PostgreSQL.

Agora vamos criar o mapeamento ORM usando o Fluent NHibernate. Clique com o botão direito sobre a pasta Mapeamento e selecione Add -> Class.

Informe o nome UsuarioMap e digite o código abaixo neste arquivo:

using Repositorio.Entidades;
using FluentNHibernate.Mapping;
namespace Repositorio.Mapeamento
{
    public class UsuarioMap :  ClassMap<Usuario>
    {
        public UsuarioMap() 
        {
            Id(c => c.Id);
            Map(c => c.Nome);
            Map(c => c.Login);
            Map(c => c.Senha);
            Map(c => c.Status);
            Table("usuarios");
        }
    }
}

Neste código, mapeamos as propriedades definidas na classe Usuário para os campos da tabela usuários, definido na propriedade Table do Fluente NHibernate.

Usamos aqui as expressões lambdas que são funções e podem conter expressões e declarações que são usadas para criar delegates e árvores de expressões onde o tipo das variáveis não precisam ser declarados, visto que elas usam métodos anônimos.

Para saber mais sobre expressões lambdas veja o artigo: .NET – Expressões Lambdas

Criando a SessionFactory e o Repositório

Vamos começar criando uma classe chamada SessionFactory, que será responsável por disponibilizar uma session que representa o nosso contexto. Nesta classe iremos definir a string de conexão e a conexão com o banco de dados PostgreSQL.

No menu PROJECT, clique em Add Class e informe o nome SessionFactory. Em seguida, digite o código abaixo nesta classe:

using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
namespace Repositorio
{
    public class SessionFactory
    {
        private static string ConnectionString = "Server=localhost; Port=5432; User Id=postgres; Password=********; Database=cadastro";
        private static ISessionFactory session;
        public static ISessionFactory CriarSession()
        {
            if (session != null)
                return session;
            IPersistenceConfigurer configDB = PostgreSQLConfiguration.PostgreSQL82.ConnectionString(ConnectionString);
            var configMap = Fluently.Configure().Database(configDB).Mappings(c => c.FluentMappings.AddFromAssemblyOf<Mapeamento.Usuario.Map>());
            session = configMap.BuildSessionFactory();
            return session;
        }
        public static ISession AbrirSession()
        {
            return CriarSession().OpenSession();
        }
    }
}

A classe SessionFactory possui métodos estáticos para criar e abrir uma sessão que representa o contexto e a conexão com o banco de dados PostgreSQL. Após isso vamos criar o nosso repositório. Nesse projeto iremos usar o padrão Repository e criar um repositório genérico onde iremos definir os métodos de acesso aos dados.

O que é o padrão Repository?

Um repositório é essencialmente uma coleção de objetos de domínio em memória e, com base nisso, o padrão Repository permite realizar o isolamento entre a camada de acesso a dados (DAL) de sua aplicação e sua camada de apresentação (UI) e camada de negócios (BLL).

Ao utilizar o padrão Repository você pode realizar a persistência e a separação de interesses em seu código de acesso a dados, visto que ele encapsula a lógica necessária para persistir os objetos do seu domínio na sua fonte de armazenamento de dados.

Em suma, você pode usar o padrão Repository para desacoplar o modelo de domínio do código de acesso a dados.

Martin Fowler afirma:

“O padrão  Repository faz a mediação entre o domínio e as camadas de mapeamento de dados, agindo como uma coleção de objetos de domínio em memória. Conceitualmente, um repositório encapsula o conjunto de objetos persistidos em um armazenamento de dados e as operações realizadas sobre eles, fornecendo uma visão mais orientada a objetos da camada de persistência e também dá suporte ao objetivo de alcançar uma separação limpa e uma forma de dependência entre o domínio e as camadas de mapeamento de dados”. (http://martinfowler.com/eaaCatalog/repository.html)

Em uma das implementações do padrão repositório podemos começar definindo uma interface que atuará como a nossa fachada de acesso aos dados. Vamos criar então uma interface chamada IUsuarioCrud.

Estando no projeto Repositório, clique no menu PROJECT e clique em Add New Item. Selecione o template Interface, informando o nome IUsuarioCrud e defina o código a seguir neste arquivo:

using System.Collections.Generic;
namespace Repositorio
{
    public interface IUsuarioCrud<T>
    {
        void Inserir(T entidade);
        void Alterar(T entidade);
        void Excluir(T entidade);
        T RetornarPorId(int Id);
        IList<T> Consultar();
    }
}

Temos, assim, uma interface definindo os métodos CRUD, que deverão ser implementados por uma classe concreta, que iremos criar e que se chamará Repositorio.vb.

Estando no projeto Repositório, clique no menu PROJECT e depois em Add Class e selecione o template Class, informando o nome Repositório e a seguir defina o código abaixo:

using NHibernate;
using System;
using System.Collections.Generic;
using NHibernate.Linq;
using System.Linq;
namespace Repositorio
{
    public class Repositorio<T> : IUsuarioCrud<T> where T : class
    {
        public void Inserir(T entidade)
        {
            using (ISession session = SessionFactory.AbrirSession())
            {
                using (ITransaction transacao = session.BeginTransaction())
                {
                    try
                    {
                        session.Save(entidade);
                        transacao.Commit();
                    }
                    catch (Exception ex)
                    {
                        if (!transacao.WasCommitted)
                        {
                            transacao.Rollback();
                        }
                        throw new Exception("Erro ao inserir Cliente : " + ex.Message);
                    }
                }
            }
        }
        public void Alterar(T entidade)
        {
            using (ISession session = SessionFactory.AbrirSession())
            {
                using (ITransaction transacao = session.BeginTransaction())
                {
                    try
                    {
                        session.Update(entidade);
                        transacao.Commit();
                    }
                    catch (Exception ex)
                    {
                        if (!transacao.WasCommitted)
                        {
                            transacao.Rollback();
                        }
                        throw new Exception("Erro ao Alterar Cliente : " + ex.Message);
                    }
                }
            }
        }
        public void Excluir(T entidade)
        {
            using (ISession session = SessionFactory.AbrirSession())
            {
                using (ITransaction transacao = session.BeginTransaction())
                {
                    try
                    {
                        session.Delete(entidade);
                        transacao.Commit();
                    }
                    catch (Exception ex)
                    {
                        if (!transacao.WasCommitted)
                        {
                            transacao.Rollback();
                        }
                        throw new Exception("Erro ao Excluir Cliente : " + ex.Message);
                    }
                }
            }
        }
        public T RetornarPorId(int Id)
        {
            using (ISession session = SessionFactory.AbrirSession())
            {
                return session.Get<T>(Id);
            }
        }
        public IList<T> Consultar()
        {
            using (ISession session = SessionFactory.AbrirSession())
            {
                return (from c in session.Query<T>() select c).ToList();
            }
        }
    }
}

Vemos no código a implementação dos métodos CRUD da interface IUsuarioCrud.

Agora só falta definir uma classe para que possamos usar o repositório genérico.

No menu PROJECT clique em Add -> Class e informe o nome UsuarioRepositorio digitando o código abaixo neste classe:

using System.Linq;
using Repositorio.Entidades;
using NHibernate;
using NHibernate.Linq;
namespace Repositorio.Mapeamento
{
    public class UsuarioRepositorio : Repositorio<Usuario>
    {
        public bool ValidarLogin(string login)
        {
	  using (ISession session = SessionFactory.AbrirSession()) 
               {
                    return (from e in session.Query<Usuario>() where e.Login.Equals(login) select e).Count() > 0;
	  }
        }
        public bool ValidarAcesso(string login, string senha)
        {
              using (ISession session = SessionFactory.AbrirSession()) 
              {
	       return (from e in session.Query<Usuario>() where e.Login.Equals(login) && e.Senha.Equals(senha) select e).Count() > 0;
	 }
        }
    }
}

A nossa classe UsuarioRepositorio herda da classe Repositorio e inclui dois métodos usando consultas LINQ:

  • ValidarLogin – que verifica se um login já esta cadastrado na tabela usuários
  • ValidarAcesso – que verifica o login e senha do usuário na tabela usuários

Estamos prontos para usar o nosso repositório para acessar e persistir informações no PostgreSQL usando a classe UsuarioRepositorio.

Na continuação deste artigo, irei mostrar a criação dos formulários de login e registro no projeto Windows Forms e mostrar como usar o nosso repositório.