DAO Genérico com JPA e Hibernate

Samuel Martins Delfim 4 de novembro de 2008 5
DAO Genérico com JPA e Hibernate
Olá pessoal,Criei uma estrutura inicial de um DAO Genérico que gostaria de compartilhar com vcs. Ainda não existe todos os métodos que vou precisar, mas vou atualizando aqui a cada mudança no código. Para esta implementação utilizei JPA + Hibernate e para meu caso vem me atendendo bem por enquanto. Segue abaixo a implementação:

/**
* Esta classe é responsável por conter as operações genéricas para realização
* do acesso aos dados do sistema.
*
* @author Samuel
*
* @param
*/
@SuppressWarnings("unchecked")
public abstract class GenericDAOImpl {

 private EntityManager entityManager;

 private Class classePersistente;

 /**
  * Contrutor que guarda o tipo atual da classe T.
  */
 public GenericDAOImpl() {
  this.classePersistente = (Class) ((ParameterizedType) getClass()
    .getGenericSuperclass()).getActualTypeArguments()[0];
 }

 /**
  * Atualiza o objeto que se encontra em memória.
  *
  * @param object
  *            objeto a ser atualizado
  */
 public final void refresh(T object) {
  getEntityManager().refresh(object);
 }

 /**
  * Executa o flush no entity manager.
  *
  */
 public final void flush() {
  getEntityManager().flush();
 }

 /**
  * Executa o flush no entity manager.
  *
  */
 public final void clear() {
  flush();
  getEntityManager().clear();
 }

 /**
  * Executa o merge do objeto que se encontra em memória.
  *
  * @param objeto
  *            a ser realizado o merge
  * @return objeto que foi executado o merge
  */
 public final T merge(T objeto) {
  objeto = getEntityManager().merge(objeto);
  return objeto;
 }

 /**
  * Salva o objeto atual na base de dados.
  *
  * @param objeto
  *            a ser salvo
  */
 public final void salvar(T objeto) {
  getEntityManager().persist(objeto);
 }

 /**
  * Remove o objeto da base de dados.
  *
  * @param objeto
  *            a ser removido
  */
 public final void remover(T objeto) {
  getEntityManager().remove(objeto);
 }

 /**
  * Remove o objeto uma vez passado sua chave como parâmetro.
  *
  * @param chave
  *            identificadora do objeto
  */
 public final void removerPorChave(Integer chave) {
  getEntityManager().createQuery(
    "delete from " + getClassePersistente().getName()
      + " where id = " + chave).executeUpdate();
 }

 /**
  * Busca o objeto uma vez passado sua chave como parâmetro.
  *
  * @param chave
  *            identificador
  * @return Objeto do tipo T
  */
 public final T buscarPorChave(Integer chave) {
  T instance = null;
  try {
   instance = getEntityManager().find(getClassePersistente(), chave);
  } catch (RuntimeException re) {
   re.printStackTrace();
  }
  return instance;
 }

 /**
  * Busca o objeto de acordo com o objeto preenchido com os valores passado
  * como exemplo.
  *
  * @param objeto
  *            utilizado para realizar a busca
  * @param ordenacoes
  *            lista de critérios de ordenação
  * @return Lista de objetos retornada
  */
 public final List buscarPorExemplo(T objeto, Order... ordenacoes) {
  Session session = (Session) getEntityManager().getDelegate();
  Example example = criaExemplo(objeto);
  Criteria criteria = session.createCriteria(objeto.getClass()).add(
    example);
  for (int i = 0; i < ordenacoes.length; i++) {
   criteria.addOrder(ordenacoes[i]);
  }
  return (List) criteria.list();
 }

 /**
  * Busca o objeto de acordo com o objeto preenchido com os valores passado
  * como exemplo.
  *
  * @param objeto
  * @param indiceInicial
  * @param indiceFinal
  * @param ordenacoes
  *            lista de critérios de ordenação.
  * @return Lista de orden
  */
 public final List buscarPorExemplo(T objeto, Integer indiceInicial,
   Integer indiceFinal, Order... ordenacoes) {
  Example example = criaExemplo(objeto);
  Criteria criteria = criaCriteria().add(example);
  criteria.setFirstResult(indiceInicial);
  criteria.setMaxResults(indiceFinal);

  for (int i = 0; i < ordenacoes.length; i++) {
   criteria.addOrder(ordenacoes[i]);
  }

  return (List) criteria.list();
 }

 /**
  * Retorna a quantidade total de objetos para aquela entidade específica.
  *
  * @return quantidade total de objetos
  */
 public final int buscaQuantidadeTotal() {
  Criteria criteria = criaCriteria();
  criteria.setProjection(Projections.rowCount());
  return (Integer) criteria.uniqueResult();
 }

 /**
  * Busca todos os objetos para aquela entidade específica.
  *
  * @param ordenacoes
  *            lista de ordenações para pesquisa
  * @return lista de todos os objetos da entidade
  */
 public List buscarTodos(Order... ordenacoes) {
  List results = null;
  try {
   Query query = getEntityManager().createQuery(
     "from " + getClassePersistente().getName()
       + adicionaOrderByHql(ordenacoes));
   results = query.getResultList();
  } catch (RuntimeException re) {
   re.printStackTrace();
  }
  return results;
 }

 /**
  *
  * Busca todos os objetos de uma entidade específica de um índice inicial
  * até um índice final.
  *
  * @param indiceInicial
  *            indice inicial da busca
  * @param indiceFinal
  *            indice final da pesquisa.
  * @param ordenacoes
  *            lista de ordenação a ser criado
  * @return uma lista de objetos do tipo T
  */
 public List buscarTodos(Integer indiceInicial,
   Integer indiceFinal, Order... ordenacoes) {
  List results = null;
  try {
   Query query = getEntityManager().createQuery(
     "from " + getClassePersistente().getName()
       + adicionaOrderByHql(ordenacoes));
   query.setFirstResult(indiceInicial);
   query.setMaxResults(indiceFinal);

   results = (List) query.getResultList();
  } catch (RuntimeException re) {
   re.printStackTrace();
  }
  return results;
 }

 /**
  * Utilizado para se injetar o Entity manager no DAO.
  *
  * @param entityManager
  *            entity manager
  */
 public void setEntityManager(EntityManager entityManager) {
  this.entityManager = entityManager;
 }

 /**
  * Utilizado para se utilizar o entity manager nos DAOS que herdam do DAO
  * genérico.
  *
  * @return Entity manager.
  */
 protected EntityManager getEntityManager() {
  return entityManager;
 }

 /**
  * Adiciona o orderBy no final da query a ser utilizada.
  *
  * @param ordenacoes
  *            a serem utilizadas para a busca
  * @return string com o orderBy
  */
 protected final static String adicionaOrderByHql(Order... ordenacoes) {
  String result = "";
  if (ordenacoes.length > 0) {
   StringBuilder builder = new StringBuilder(" order by ");
   for (int i = 0; i < ordenacoes.length - 1; i++) {
    builder.append(ordenacoes[i].toString());
    builder.append(", ");
   }
   builder.append(ordenacoes[ordenacoes.length - 1]);
   result = builder.toStri
ng();
  }

  return result;
 }

 /**
  * Busca a classe persistente do objeto utilizado na classe.
  *
  * @return classe persistente
  */
 protected final Class getClassePersistente() {
  return classePersistente;
 }

 /**
  * Retorna o objeto da clases Criteria.
  *
  * @return um objeto do tipo Criteria do Hibernate
  */
 protected final Criteria criaCriteria() {
  Session session = (Session) getEntityManager().getDelegate();
  return session.createCriteria(getClassePersistente());
 }

 /**
  * Método utilizado para criar o objeto Example. Este objeto é utilizado
  * para realizar a busca por exemplo.
  *
  * @param objeto
  *            sobre o qual o Example será criado
  * @return em objeto do tipo Example
  */
 protected final Example criaExemplo(T objeto) {

  Example example = Example.create(objeto);
  example.enableLike(MatchMode.ANYWHERE);
  example.excludeZeroes();
  example.ignoreCase();

  return example;
 }
}

Para ilustrar como esta classe é utilizada mostrarei abaixo como extender este DAO genérico:

public class PessoaDAO extends GenericDAOImpl {

    public List buscarTodosTelefoneEndereco(Integer indiceInicial, Integer indiceFinal,
            Order... ordenacoes) {
        List pessoas = super.buscarTodos(indiceInicial, indiceFinal,
                ordenacoes);

        for (Pessoa pessoa : pessoas) {
            // Carrega os relazionamentos que são LAZY. Este método chama o
            // método initialize do Hibernate.
            pessoa.getTelefones().size();
            pessoa.getEnderecos().size();
        }

        return pessoas;
    }

    @SuppressWarnings("unchecked")
    public List buscarTodosHQL() {
        Query query = getEntityManager().createNamedQuery("selectAllHQL");
        List pessoas = query.getResultList();

        return pessoas;
    }

    @SuppressWarnings("unchecked")
    public List buscarTodosSQL() {

        Query query = getEntityManager().createNamedQuery("selectAllNativo");
        List pessoas = query.getResultList();

        return pessoas;
    }

    @SuppressWarnings("unchecked")
    public List buscarTodosComTelefone() {

        List resultado = new ArrayList();
        Query query = getEntityManager().createNamedQuery("selectAllNativoTelefone");

        List resultados = query.getResultList();
        for (Object object : resultados) {
            Object[] arranjo = (Object[]) object;
            Pessoa pessoa = (Pessoa) arranjo[0];
            Telefone telefone = (Telefone) arranjo[1];
            Collection telefones = new ArrayList();
            telefones.add(telefone);
            pessoa.setTelefones(telefones);

            resultado.add(pessoa);
        }

        return resultado;
    }

Em breve postarei como realizo a injeção do Entity Manager utilizando a classe DAOFactory. Qualquer dúvida ou coisa que precisarem me mandem mensagem.

5 Comentários »

  1. Fernando Scherrer 4 de novembro de 2008 de 10:44 pm - Reply

    Haw!

      Só uma sugestão: coloca os códigos entre tags <pre></pre>, assim não fica com a identação zuada (se você copiar de um lugar [eclipse, netbeans, etc] que esteja identado) fica mais fácil de ler.
      (assim)
      E se quiser deixar mais pro ainda, dá uma googleada por code highlight blogger que tem umas coisas interessantes.

    Valewz!? E valeu por compartilhar.

  2. Samuel Martins Delfim 5 de novembro de 2008 de 3:09 pm - Reply

    Obrigado pela dica Fernando…

  3. Paulo 7 de dezembro de 2008 de 7:05 pm - Reply

    Olá estou começando com JPA e li seu codigo sobre DAO generico e fiquei em duvida onde se le o nome que colocou no arquivo persistence.xml ???? como identifico ????

  4. Samuel Martins Delfim 15 de dezembro de 2008 de 3:53 pm - Reply

    Olá Paulo,

    Não sei se eu entendi direito, mas o arquivo persistence.xml deve ser colocado dentro da pasta META-INF dentro do diretório onde se encontram os códigos fontes.

    Automaticamente, se o seu arquivo estiver dentro desta pasta ele será reconhecido e utilizado como arquivo de configuração.

    Dentro do arquivo persistence vc configura o acesso ao banco.

    Qualquer problema me avise…

  5. Marcelo 28 de fevereiro de 2011 de 1:45 am - Reply

    Sei que o objetivo não é esse, mas não seria melhor utilizar StringBuffer ao invés de StringBuilder?

Deixe uma resposta »