Nas próximas semanas vou dedicar algum tempo livre a estudar o NHibernate.
Já ouvi falar muito bem deste ORM mas quando comecei a tentar estudá-lo e aprender a utilizá-lo comecei a achar que era bastante complicado! Agora que começo a entender melhor a arquitectura dele começo a reparar que não é tão complicado assim, o meu problema foi encontrar material para estudar. Para ser sincero estou fechado no quarto desde ontem ao final da tarde, só para conseguir entender o que vou escrever neste artigo..
Por isso decidi começar a escrever uma jornada de artigos sobre a iniciação de NHibernate! Á medida que for aprendendo novos recursos vou postando no meu blog.
No final do post vou deixar alguns links úteis sobre NHibernate.
Se acontecer alguem reparar em erros por favor avise-me, ainda estou a iniciar-me neste ORM e gostava de ganhar boas bases nele.
Quem quiser fazer download do projecto pode fazê-lo aqui: http://github.com/guilherme-cardoso/NHibernate---Introdu--o/downloads
NHibernate
O NHibernate é um ORM baseado noutro ORM para Java, o Hibernate. A função dele é mapear a classe do nosso projecto com a base de dados sem termos de nos preocupar com comandos SQL.
Mais abaixo na parte dos métodos, vamos reparar em três interfaces usadas (á excepção da IQuery que vai ficar mais para a frente):
- ISession - representa uma pela conecção com a base de dados
- ITransaction - representa uma transacção controlada pelo NHibernate
- IQuery - representa uma consulta á base de dados
Estas três interfaces pertencem á assembly NHibernate.dll
Um bom exemplo que posso mostrar de onde a utilização de um ORM ia
facilitar-me bastante a vida enquanto programador é um post que escrevi
há pouco mais de um ano aqui: http://pontonetpt.com/blogs/guilhermecardoso/archive/2009/05/19/P29173.aspx
Infelizmente esse método de uso de DataTables e DataSets ainda é o
método de aprendizagem na maioria das Escolas Profissionais.
Instalação
Ao contrário do Entity Framework que já vem incorporado no Visual Studio, o NHibernate requere uma instalação manual.
É muito simples, basta fazer-mos download do NHibernate (link). Quando criar-mos um novo projecto adicionamos as seguintes referências:
- NHibernate.dll (NHibernate-2.1.2.GA-bin\Fluent NHibernate)
- NHibernate.ByteCode.Castle.dll (NHibernate-2.1.2.GA-bin\Fluent NHibernate)
- Castle.Core.dll (NHibernate-2.1.2.GA-bin\Fluent NHibernate)
Para mais tarde voltar a criar projectos sem ter de fazer download do NHibernate novamente, extraí o download para uma pasta no C:/ e sempre que quero criar novos projectos, adiciono as referências apartir de lá.
O uso de uma proxy é requirido pelo NHibernate. Neste exemplo estou a usar a Castle mas não vou falar dela neste artigo pois não sei do que se trata! Mais tarde lá irei.
Configuração
Para configurar o NHibernate vi em bastantes tutoriais criarem o arquivo hibernate.cfg.xml e quando é chamado o método Configure() da assembly NHibernate.Cfg.Configuration o NHibernate vai procurar esse arquivo e aplicar as configurações.
Eu preferi criar dentro do próprio Web.Config.
Aseguir á tag <ConfigSections> (percente à <configuration) adiciona-mos uma nova secção para depois adicionar-mos a configuração do NHibernate com o nome dessa secção (hibernate-configuration):
<configuration>
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
</configSections>
Aseguir á tag </configSections> é que inseri a configuração do NHibernate.
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory>
<property name="dialect">
NHibernate.Dialect.MsSql2005Dialect
</property>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Server=Computador\SQLEXPRESS;
Database=NHibernate;
Integrated Security=True;
</property>
<property name="proxyfactory.factory_class">
NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle
</property>
</session-factory>
</hibernate-configuration>
Vão precisar de alterar o nome do vosso servidor SQL na propriedade connection.connection_string. O nome aparece quando iniciam o SQL Server 2005 (na caixa de diálogo para conectarem-se ao servidor).
Estou a usar um servidor SQL Server 2005. Se
não estiverem a trabalhar com estas base de dados, podem ver um artigo
que o Leandro Ribeiro escreveu sobre base de dados suportadas pelo
NHibernate: http://pontonetpt.com/blogs/leandroribeiro/archive/2008/02/22/P26588.aspx
Mapeamentos
Configurado o NHibernate vamos criar os mapeamentos.
Agora a início vou fazer os mapeamentos usando arquivos .XML (tradicional do NHibernate), mas mais para a frente vou recorrer ao Fluent NHibernate. O Fluent NHibernate permite-nos fazer os nossos mapeamentos em código (ao invés de arquivos XML) e também tem a particularidade de criar mapeamentos automáticos apartir das nossas entidades (não sei se para NHibernate também exista algo que crie em XML mas para já não vale a pena ver isso).
Para estruturar melhor o nosso projecto, vamos criar uma pasta com o nome Mapeamentos. Dentro dessa pasta vamos criar um arquivo XML com o nome Noticias.hbm.xml.
Um aspecto importante é a extensão .hbm.xml. O NHibernate vai reconhecer todos os arquivos que contenham hbm antes da extensão .xml como arquivos de mapeamento.
Antes de começar-mos a escrever o nosso mapeamento vamos utilizar um esquema xml que vinha no download que fizemos a ínicio para que o Visual Studio e o IntellIsense nos facilite o trabalho enquanto estivermos a escrever o código. O arquivo chama-se nhibernate-mapping.xsd e está dentro da pasta Required_Bins. Para alterar-mos o esquema entramos dentro do ficheiro Noticias.hbm.xml, metemos o cursor dentro da área de código como se fossemos escrever algo e na janela das propriedades vai aparecer um campo com o nome Schemas. Aí vamos indicar onde está o ficheiro nhibernate-mapping.xsd
Para já vamos criar apenas uma tabela com o nome Noticias e três colunas: Id, Titulo e Corpo.
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NH" namespace="NH.Dominio">
<class name="Noticias" table="Noticias">
<id name="Id" column="Id">
<generator class="native" />
</id>
<property name="Titulo"></property>
<property name="Corpo"></property>
</class>
</hibernate-mapping>
A namespace NH.Dominio está a indicar onde temos a Entidade referente a este mapeamento (que vamos criar aseguir).
A coluna Id é representada com a própria tag <id> e como neste exemplo é de auto-incrementação, defenimos a generator com a class native.
As propriedades são as restantes tabelas.
Entidades
As entidades são escritas em código. São os objectos dos nossos mapeamentos.
Dentro da pasta Dominio vamos criar um arquivo de classe com o nome Noticias.cs.
Vamos criar uma classe (tabela) com o nome Noticias e declarar 3 objectos: Id, Titulo e Corpo
namespace NH.Dominio
{
public class Noticias
{
public virtual Int32 Id { get; set;}
public virtual string Titulo { get; set; }
public virtual string Corpo { get; set;}
}
}
É preciso atribuir a propriedade virtual ás variáveis para que o NHibernate possa trabalhar com elas.
Contexto
Esta camada vai ser responsável ligação entre o nosso programa e o NHibernate, que por sua vez se liga á base de dados.
public class Contexto
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if(_sessionFactory == null)
{
string directoria = System.Web.HttpContext.Current.Server.MapPath(@"~/Dominio/");
NHibernate.Cfg.Configuration configuration = new NHibernate.Cfg.Configuration();
configuration.AddXmlFile(directoria + "Noticias.hbm.xml");
configuration.Configure();
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
Ela apenas vai criar uma nova sessão se a mesma ainda não tiver sido criada (na condição _sessionFactory == null).
É também aqui que vamos incluir o nosso mapeamento das Noticias nas configurações do NHibernate. Eu criei a string directoria para obter indicar o caminho quando adicionei o arquivo XML.
Métodos CRUD (Create, Read, Update e Delete)
Agora que temos o NHibernate configurado, criá-mos os mapeamentos e entidades podemos escrever os métodos CRUD.
Os métodos CRUD vamos colocar numa camada á parte que vamos criar, a camada Dal.cs. Isto vai ajudar-nos a manter a esturutra do nosso programa organizada.
Inserir
public void Noticias_Adicionar(Noticias noticia)
{
using (ISession session = Contexto.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(noticia);
transaction.Commit();
}
}
Apagar
public void Noticias_Apagar(Noticias noticia)
{
using (ISession session = Contexto.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete(noticia);
transaction.Commit();
}
}
O método para apagar uma notícia é semelhante ao de inserir. A diferença que notamos é na interface session, em vez de salvar-mos chamamos o método Delete para apagar a notícia em questão.
Correcção: Não é necessário fechar a sessão (Session.Close) como eu a início expliquei pois ao bloco using, a variável Session vai ficar liberada da memória automaticamente.
Actualizar
public void Noticias_Actualizar(Noticias noticia)
{
using (ISession session = Contexto.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Update(noticia);
transaction.Commit();
}
}
Mais uma vez, a única diferença que notamos é o Update.
Ler por ID
public Noticias Noticias_Devolver_PorId(int id)
{
using (ISession session = Contexto.OpenSession())
{
return session.Get<Noticias>(id);
}
}
Retornar uma Lista
public List<Noticias> Noticias_Devolver()
{
using (ISession session = Contexto.OpenSession())
{
return session.CreateCriteria(typeof(Noticias)).List<Noticias>();
}
}
O método em cima mostra como retornar uma Lista. Se virem este projecto (o link está no inicio do artigo), eu estou a preencher uma DropDownListrecorrendo a este método. Basta indicarmos o DataSource da DropDownLis (DropDownListNoticias.DataSource = dal.NoticiasDevolver();
E prontos, este foi o meu primeiro artigo relacionado com NHibernate.
Agora vou tentar analisar melhor o que aprendi nestas horas (se soubessem o que foram as minhas últimas 32 horas á custa disto!) e tentar melhorar o código que escrevi, nomeadamente o da classe contexto.
Aproveito para agradecer ao Ricardo Peres por me ter encaminhado um pouco e para pedir desculpas à Mafalda pelo tempo ausente ;)
Alguns links úteis:
NHibernate Portugal (mailling list na google): http://groups.google.com/group/nhpt
NHusers (mailling list na google): http://groups.google.com/group/nhusers
NHibernate fórum: https://forum.hibernate.org/viewforum.php?f=25