Veja nesse artigo como criar uma abstração para fazer a persistência dos dados utilizando o framework NHibernate. Essa prática facilita a criação da camada de persistência das novas entidades que surgirem no contexto da aplicação, assim podemos a partir de uma simples herança obter uma classe completa com todas as operações do famoso CRUD.

Como o foco desse artigo é mostrar como criar a abstração, foi desenvolvido um simples exemplo para demonstração. Esse exemplo está disponível para download e contém duas maneiras de implementação, com e sem abstração. Para facilitar o entendimento do exemplo, não estou usando princípios como Injeção de Dependência ou Inversão de Controle.

Para explicar como fazer a abstração, vamos criar uma classe genérica. Vou mostrar passo a passo uma refatoração de código, e após a refatoração, veremos que ficará muito mais fácil implementar a camada de persistência para novas entidades.

Para iniciar vamos pensar no seguinte modelo (Figura 1), onde temos uma classe que representa os autores e outra representando os livros. A principio para cada entidade temos uma implementação na camada de persistência.

Modelo de classes

Figura 1: Modelo de classes

A nossa camada de persistência (sem abstração) é composta de uma interface e um classe de implementação (poderia ter mais) para cada entidade, vamos ver na listagem 1 a interface de persistência para a entidade Author, e na listagem 2 a implementação desta interface.

Listagem 1. Interface de persistência da entidade Author


public interface IAuthorDAO
{
    Int64 Save(Author author);
 
    void Update(Author author);
 
    void Delete(Author author);
 
    Author Find(Int64 id);
 
    IList List();
}

Listagem 2. Implementação da classe de persistência da entidade Author


public class NHibernateAuthorDAO : IAuthorDAO
{
    private ISession _session;
 
    public NHibernateAuthorDAO(ISession session)
    {
        _session = session;
    }
 
    #region IAuthorDAO Members
 
    public Int64 Save(Author author)
    {            
        return (Int64)_session.Save(author);                        
    }
 
    public void Update(Author author)
    {         
        _session.Update(author);
    }
 
    public void Delete(Author author)
    {            
        _session.Delete(author);
    }
 
    public Author Find(long id)
    {            
        return _session.Get(id);
    }
 
    public IList List()
    {            
        return _session.CreateCriteria(typeof(Author)).List();   
    }
 
    #endregion
}

Dessa maneira já temos uma camada de persistência funcional, porém para cada entidade teríamos que criar uma interface e fazer a implementação. Vamos ver agora como abstrair as operações CRUD em uma classe genérica. Para começar vamos criar uma interface genérica (listagem 3), nessa interface vamos ter todos os métodos comuns entre as entidades, e teremos a opção de definir para qual entidade a interface deverá trabalhar.

Listagem 3. Interface genérica de persistência


public interface IBaseDAO
{
    long Save(T entity);
 
    void Update(T entity);
 
    void Delete(T entity);
 
    T Find(long id);
 
    IList List();        
}

Notem que a interface não tem ligação com nenhuma entidade, ela trabalha através de um tipo T que será definido com herança para cada entidade. Vamos ver agora a implementação da interface, que também será genérica (listagem 4).

Listagem 4. Implementação genérica de persistência


public abstract class NHibernateBaseDAO : IBaseDAO
{
    private ISession _session;
 
    public NHibernateBaseDAO(ISession session)
    {
        _session = session;
    }
 
    #region IBaseDAO Members
 
    public long Save(T entity)
    {
        return (long)_session.Save(entity);
    }
 
    public void Update(T entity)
    {
        _session.Update(entity);
    }
 
    public void Delete(T entity)
    {
        _session.Delete(entity);
    }
 
    public T Find(long id)
    {
        return _session.Get(id);
    }
 
    public IList List()
    {
        IList list = _session.CreateCriteria(typeof(T)).List();
        return list;
    }
 
    #endregion
}

Percebam que essa implementação é semelhante a uma implementação especifica para uma entidade, porém ela faz as operações para um tipo T. Esse tipo T vai representar cada tipo de entidade, a definição de qual será a entidade que a classe vai persistir será através de herança, por isso a nossa classe genérica é abstrata.

Com a interface e a classe genérica prontas, podemos começar implementar a persistência para cada entidade. Vamos continuar com a nossa refatoração, e alterar classe NHibernateAuthorDAO da listagem 2, para que essa utilize os métodos da nossa classe genérica, e assim não precise implementar os métodos das operações CRUD. Vamos ver então na listagem 5 a interface e na listagem 6 a implementação da classe.

Listagem 5. Interface de persistência a partir da interface genérica


public interface IAuthorDAO : IBaseDAO
{
}
 

Listagem 6. Classe de persistência a partir da classe genérica


public class NHibernateAuthorDAO : NHibernateBaseDAO, IAuthorDAO
{
    public NHibernateAuthorDAO(ISession session) : base(session) { }
}
 

Agora vamos comparar a listagem 5 com a listagem 1, e a listagem 6 com a listagem 2. Notem como fica mais simples a implementação, conseguimos através de uma classe genérica, abstrair todas as operações CRUD, e assim evitamos a duplicação de código. Outra vantagem que agora conseguimos implementar a camada de persistência de novas entidades de forma super rápida.

E é isso pessoal, espero que esse post possa ajuda-los, estou a disposição para qualquer duvida. Um abraço e até a próxima.