Blog «EM1£1Ø»2HÐ

Porque compartilhar conhecimento é evoluir!

Introdução

Este tutorial será dividido em duas partes.

  1. Criação do projeto, definição dos objetos de domínio e seus repositórios, instalação e configuração do NHibernate.
  2. 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.

Categorias: Tutoriais Tags: ,

Leave a Reply