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:
- Visual Studio 2013 Express for windows desktop
- Linguagem C#
- NHibernate 4.0
- Fluent NHibernate
- Provedor Npgsql para conexão com o PostGreSQL
- PostgreSQL 9.3
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:
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:
Na janela New DataBase informe o nome do banco de dados – Cadastro e defina o Owner como sendo o usuário postgres:
Agora vamos criar a nossa tabela usuarios que deverá possuir a seguinte estrutura:
Para isso faça o seguinte:
- Selecione o objeto Tables()
- Clique no menu SQL
- 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) )
- Clique no botão para executar a instrução e criar a tabela no banco de dados Cadastro.
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:
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.
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.
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:
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.
Na janela – Manage Nuget Packages – digite NHibernate para localizar o pacote e, a seguir, clique no botão Install.
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:
Retorne a janela – Manage Nuget Packages – e digite Npgsql para localizar o pacote e a seguir clique no botão Install.
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.