Introdução
Este tutorial será dividido em duas partes.
- Criação do projeto, definição dos objetos de domínio e seus repositórios, instalação e configuração do NHibernate.
- Criação da aplicação em usando Windows Forms e integrando com a parte de persistência.
Esse tutorial é baseado no artigo Your first NHibernate based application
NHibernate
O NHibernate é um framework open source, desenvolvido usando .NET framework, baseado no Hibernate do Java, que possibilita o mapeamento de objetos-relacionais(ORM).
Visão geral em alto nível de como trabalha o NHibernate
Basicamente tem-se a aplicação com seus objetos persistentes que são usados pelo NHibernate, mapeados por XML(ou Atributtes) onde relaciona-se a classe e seus atributos com a tabela e suas colunas. O NHibernate precisa de alguns arquivos de configuração para funcionar e conectar no banco de dados.
Mais o que é ORM?
É uma técnica de desenvolvimento para fazer uma abstração do banco de dados usando orientação a objetos, onde as tabelas do banco são representadas por classes.
Usando o ORM caí muito à necessidade de escrever SQL para inserir, remover, atualizar ou consultar dados no banco, pois geralmente essas SQL serão geradas automaticamente.
Obviamente não vai excluir por completo a necessidade de escrever código SQL(Query), pois existem casos onde o ORM não consegue atender.
Nesses casos você tem que escrever a query. Isso geralmente acontece quando é uma query é bem customizada.
A forma como o mapeamento é feito varia da ferramenta(ou framework) que estiver usando. No Hibernate em java você pode fazer o mapeamento tanto usando XML, quanto usando as Anotações. No NHibernate o mapeamento pode ser feito também com XML ou usando Attributes.
Para informações mais afundo sobre ORM Visite esse link(en)
Sobre a Aplicação
Nossa aplicação será bem simples, usando um banco de dados local (SQL Server Compact Edition). Uma aplicação Windows form que vai listar, inserir, editar e excluir dados de uma pessoa que pertencem a uma categoria. Categoria pode possuir uma ou várias pessoas.
Representação UML das classes da aplicação
DER do banco da aplicação
Um pequeno detalhe, é que no nosso mapeamento o ID não vai ser um int vai ser um Guide. Isso é só uma representação de como vai ficar as colunas nas tabelas.
Criei um projeto “PrimeraAplicacaoNHibernate”
Criando o projeto da aplicação
Criando Estrutura de Pastas
Crie as pasta de acordo com a figura abaixo:
Estrutura de pasta da aplicação
Descrição dos diretórios:
- Dados – Diretório que conterá banco de dados
- Domínio – Diretório que conterá classes de domínio (entidades persistentes)
- Lib – Diretório onde ficara as .dlls
- Mapeamentos – Diretório que conterá os arquivos de mapeamentos .hbm.xml
- Repositório – Diretório que conterá as classes para fazer a persistência.
Criando Banco de Dados Local
Crie um banco de dados local dentro da pasta “Dados”. Crie um banco chamado “BancoDaAplicacao.sdf”
Criando o banco da aplicação
Baixando e Instalando NHibernate
Baixe o NHibernate nesse link
Descompacte o arquivo e copie para a pasta Lib as bibliotecas que aparecem figura abaixo:
Dlls que deve estar na pasta Lib da aplicação
A dll System.Data.SqlServerCe.dll pode ser encontrada em “Arquivos de Programa(Program Files)\ Microsoft SQL Server Compact Edition\v3.5\Desktop”. As outras serão encontradas “Microsoft SQL Server Compact Edition\v3.5”.
Adicione referencias as dlls System.Data.SqlServerCe.dll , NHibernate.dll, LinFu.DynamicProxy.dll e NHibernate.ByteCode.LinFu.dll. Nas propriedades de cada no campo “Copy Local” coloque “True”.
No Windows 7 x64 tive problemas com a System.Data.SqlServerCe.dll. Quando chega na parte “configuration.BuildSessionFactory()“, uma exceção era lançada com a mensagem “Could not create the driver from NHibernate.Driver.SqlServerCeDriver“. Para resolver isso tive que instalar uma atualização do SQL Server Compact.
Configurando com hibernate.cfg.xml
O NHibernate precisa de um arquivo de configuração chamado hibernate.cfg.xml que conterá as configurações do tipo: mostrar SQL; string de conexão. Crie esse arquivo na raiz da aplicação. Nas propriedades do hibernate.cfg.xml a propriedade “Copy to Output” tem que estar “Copy always”.
Abaixo, o código de como a configuração do hibernate.cfg.xml deve ficar:
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="dialect">
NHibernate.Dialect.MsSqlCeDialect
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlServerCeDriver
</property>
<property name="connection.connection_string">
Data Source=Dados\BancoDeDadosAplicacao.sdf
</property>
<property name="show_sql">false</property>
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu
</property>
</session-factory>
</hibernate-configuration>
Os parâmetros “connection.provider”, “dialect”, “connection.driver_class”, “connection.connection_string”, são referentes a conexão. O parâmetro connection.connection_string diz onde conectar(no nosso caso é um banco local, então informa-se o caminho do banco). O parâmetro show_sql informa se as querys geradas devem ser mostradas.
Se você tiver muitos problemas com o banco local. Faça download e instale o SQL Server Express e o SQL Server Management.
Link do Microsoft SQL Server 2005 Express Edition
Link do Microsoft SQL Server Management Studio Express
Se você está usando Windows 7 provavelmente vai ter que instalar uma atualização do SQL Server 2005
Link da atualização Microsoft SQL Server 2005 Express Edition Service Pack 3
Não vou detalhar como instalar o SQL Server. Depois de instalar e configurar crie uma nova base de dados “BancoDeDadosAplicacao“.
Usando o SQL Server o hibernate.cfg.xml deve sofre algumas modificações.
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="dialect">
NHibernate.Dialect.MsSql2005Dialect
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Data Source=.\SQLEXPRESS; Integrated Security=True; Initial catalog=BancoDeDadosAplicacao; User Id=sa;Password=sa
</property>
<property name="show_sql">false</property>
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu
</property>
</session-factory>
</hibernate-configuration>
Esse usuário “sa” já vem por padrão no SQL Server. “Initial catalog” informa o nome da base de dados.
Criando objetos de domínio e seus mapeamentos
Depois de ter copiado as dlls e escrito os arquivos de configuração, vamos criar os objetos de domínio e seus mapeamentos. As classes de domínio serão criadas na pasta “Dominio” os arquivos .hbm.xml serão criados na pasta “Mapeamentos”.
Categoria.cs
using System;
namespace PrimeraAplicacaoNHibernate.Dominio
{
public class Categoria
{
public virtual Guid Id { get; set; }
public virtual string Descricao { get; set; }
}
}
Categoria.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="PrimeraAplicacaoNHibernate"
namespace="PrimeraAplicacaoNHibernate.Dominio">
<class name="Categoria" table="categoria">
<id name="Id">
<generator class="guid" />
</id>
<property name="Descricao" />
</class>
</hibernate-mapping>
Pessoa.cs
using System;
namespace PrimeraAplicacaoNHibernate.Dominio
{
public class Pessoa
{
public virtual Guid Id { get; set; }
public virtual string Nome { get; set; }
public virtual string SobreNome { get; set; }
public virtual bool Sexo { get; set; }
public virtual DateTime DataNascimento { get; set; }
public virtual Categoria Categoria { get; set; }
}
}
Pessoa.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="PrimeraAplicacaoNHibernate"
namespace="PrimeraAplicacaoNHibernate.Dominio">
<class name="Pessoa" table="pessoa">
<id name="Id">
<generator class="guid" />
</id>
<property name="Nome" />
<property name="SobreNome" />
<property name="Sexo" />
<property name="DataNascimento" />
<many-to-one name="Categoria" class="PrimeraAplicacaoNHibernate.Dominio.Categoria" column="categoria_id" cascade="none"/>
</class>
</hibernate-mapping>
Observe que no mapeamento de Pessoa tem um “many-to-one” que indica que categoria pode ter várias pessoas e pessoa pertence a uma categoria. O many-to-one que representa a relação da pessoa com a categoria, lá na tabela pessoa tem uma foreign key de categoria_id que referencia a tabela categoria. Na classe pessoa tem-se uma propriedade que é do tipo Categoria.
Um detalhe é a palavra “virtual” antes do tipo de retorno, essa palavra é obrigatória para propriedades persistentes. Colocar o método virtual é permitir que ele seja sobrescrito.
Gerando as tabelas
Vamos fazer um pequeno teste de unidade que gera as tabelas no banco local. Mas antes de escrever o teste, adicione nas referencias as dlls do nunit. “nunit.core.dll” e “nunit.framework.dll”
TesteParaGerarTabelas.cs
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
using PrimeraAplicacaoNHibernate.Dominio;
namespace PrimeraAplicacaoNHibernate
{
[TestFixture]
public class TesteParaGerarTabelas
{
[Test]
public void testeIniciacao()
{
var cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly(typeof(Categoria).Assembly);
new SchemaExport(cfg).Execute(false, true, false);
}
}
}
Antes de iniciar a aplicação rode o teste (só uma vez), para criar as tabelas. Depois de rodar não precisa mais rodar de novo (só se criar um novo objeto de domínio e seu mapeamento).
Iniciando o CRUD da aplicação
Vamos trabalhar com a metodologia onde, para cada objeto de domínio temos uma classe repositório que é responsável por persisti-lo (parecido com a solução BOLOVO).
Antes de criar as classes de repositório, vamos criar um helper para nos ajudar com a sessão do NHibernate.
NHibernateHelper.cs
using NHibernate;
using NHibernate.Cfg;
using PrimeraAplicacaoNHibernate.Dominio;
namespace PrimeraAplicacaoNHibernate.Repositorio
{
public class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(Categoria).Assembly);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
}
Agora sim! Vamos criar nossas classes de repositório, mas primeiro vamos definir uma interface básica para o repositório implementar.
IRepositorioCategoria.cs
using System;
using System.Collections.Generic;
using PrimeraAplicacaoNHibernate.Dominio;
namespace PrimeraAplicacaoNHibernate.Repositorio
{
public interface IRepositorioCategoria
{
void Add(Categoria categoria);
void Update(Categoria categoria);
void Remove(Categoria categoria);
Categoria GetById(Guid categoriaId);
Categoria GetByDescricao(string descricao);
ICollection<Categoria> GetList();
}
}
RepositorioCategoria.cs
using System;
using System.Collections.Generic;
using PrimeraAplicacaoNHibernate.Dominio;
using NHibernate;
using NHibernate.Criterion;
namespace PrimeraAplicacaoNHibernate.Repositorio
{
public class RepositorioCategoria : IRepositorioCategoria
{
public void Add(Categoria categoria)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(categoria);
transaction.Commit();
}
}
public void Update(Categoria categoria)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Update(categoria);
transaction.Commit();
}
}
public void Remove(Categoria categoria)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete(categoria);
transaction.Commit();
}
}
public Categoria GetById(Guid productId)
{
using (ISession session = NHibernateHelper.OpenSession())
return session.Get<Categoria>(productId);
}
public ICollection<Categoria> GetList()
{
using (ISession session = NHibernateHelper.OpenSession())
{
var categorias = session.CreateCriteria(typeof(Categoria)).List<Categoria>();
return categorias;
}
}
public Categoria GetByDescricao(string descricao)
{
using (ISession session = NHibernateHelper.OpenSession())
{
Categoria product = session
.CreateCriteria(typeof(Categoria))
.Add(Restrictions.Eq("Descricao", descricao))
.UniqueResult<Categoria>();
return product;
}
}
}
}
IRepositorioPessoa.cs
using System;
using System.Collections.Generic;
using PrimeraAplicacaoNHibernate.Dominio;
namespace PrimeraAplicacaoNHibernate.Repositories
{
public interface IRepositorioPessoa
{
void Add(Pessoa pessoa);
void Update(Pessoa pessoa);
void Remove(Pessoa pessoa);
Pessoa GetById(Guid pessoaId);
Pessoa GetByNome(string nome);
ICollection<Pessoa> GetByCategory(Categoria categoria);
}
}
RepositorioPessoa.cs
using System;
using System.Collections.Generic;
using PrimeraAplicacaoNHibernate.Dominio;
using NHibernate;
using NHibernate.Criterion;
namespace PrimeraAplicacaoNHibernate.Repositories
{
public class RepositorioPessoa : IRepositorioPessoa
{
public void Add(Pessoa product)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(product);
transaction.Commit();
}
}
public void Update(Pessoa product)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Update(product);
transaction.Commit();
}
}
public void Remove(Pessoa product)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete(product);
transaction.Commit();
}
}
public Pessoa GetById(Guid productId)
{
using (ISession session = NHibernateHelper.OpenSession())
return session.Get<Pessoa>(productId);
}
public Pessoa GetByNome(string nome)
{
using (ISession session = NHibernateHelper.OpenSession())
{
Pessoa product = session
.CreateCriteria(typeof(Pessoa))
.Add(Restrictions.Eq("Nome", nome))
.UniqueResult<Pessoa>();
return product;
}
}
public ICollection<Pessoa> GetByCategory(Categoria categoria)
{
using (ISession session = NHibernateHelper.OpenSession())
{
var products = session
.CreateCriteria(typeof(Pessoa))
.CreateCriteria("Categoria", "categoria")
.Add(Restrictions.Eq("categoria.Id", categoria.Id))
.List<Pessoa>();
return products;
}
}
}
}
Bom, com isso encerra-se a criação da arquitetura básica para criação da aplicação. Na próxima parte vamos criar a a parte de visão da aplicação com windows form que usará as classe criadas até agora.








