Inicial > hibernate, programação > Usando ResultTransformer personalizado na sua consulta com Hibernate

Usando ResultTransformer personalizado na sua consulta com Hibernate

No post “Como retornar e preencher apenas alguns atributos da entidade na consulta com Hibernate” mostrei como usar a classe AliasToBeanResultTransformer junto com HQL. A classe fornecida pelo próprio Hibernate é realmente muito útil, acontece que se você tem alguma consulta SQL através do método createSQLQuery (da classe org.hibernate.Session), pode ter passado pelo problema que tive essa semana. Infelizmente a classe AliasToBeanResultTransformer não funciona com SQLQuery quando, entre os atributos retornados, há  Enumerations. Outro problema é quando temos atributos de entidades relacionadas. A reflexão empregada por essa classe auxiliar não consegue instanciar e preencher as dependências entre a classe principal e seus relacionamentos.

Vamos ao exemplo abaixo:

public Bem pesquisaDadosDoBemParaPesquisa(Integer codigo) {
   Bem bem = new Bem();
   StringBuffer consulta = new StringBuffer("select b.cd_bem as codigo, b.ds_bem as descricao, b.tombamento, b.tipo_bem as \"tipoBem\", l.ds_local as \"local.descricao\" from bem b inner join local l on l.cd_local = b.cd_local where b.cd_bem = ?");
   try {
      getHibernate().beginTransaction();
      Query query = getHibernate().getSession().createSQLQuery(consulta.toString());
      query.setParameter(0, codigo);
      query.setResultTransformer(new AliasToBeanResultTransformer());
      bem = (Bem) query.uniqueResult();
      getHibernate().commit();
   } catch (HibernateException e) {
      e.printStackTrace();
      getHibernate().rollback();
      throw e;
   } finally {
      getHibernate().close();
   }
   return bem;
}

Como dito anteriormente, essa query não vai funcionar. Vamos aos motivos: na consulta acima queremos trazer o tipo do Bem – atributo tipoBem, porém ele é um Enumeration e está armazenado no banco como String. A classe AliasToBeanResultTransformer não trabalha bem com Enumerations.  Outro problema está no fato de se tentar recuperar a descrição do local do Bem (alias local.descricao). A entidade Local tem relacionamento ManyToOne com a entidade Bem. Acontece que o ResultTransformer utilizado não realizará a instanciação de um Local, não setará sua descrição e, muito menos, irá associá-lo ao Bem corrente.

Solução

Uma saída é criar seu próprio ResultTransformer. No meu caso, criei uma classe chamada BemTransformer. Essa classe deve implementar a interface ResultTransformer que obriga  a declaração de dois métodos: transformList(lista) e transformTuple(valores, alias). Vamos ao código abaixo (observe principamente os comentários):

public class BemTransformer implements ResultTransformer {
   private static final long serialVersionUID = 8767683063836706565L;

   @SuppressWarnings("rawtypes")
   @Override
   public List transformList(List list) {
      return list;
   }

   @Override
   public Object transformTuple(Object[] valores, String[] alias) {
      Bem bem = new Bem();
      bem.setCodigo((Integer) valores[0]); // alias codigo
      bem.setDescricao((String) valores[1]); // alias descricao
      bem.setTombamento((Integer) valores[2]); // coluna tombamento
      bem.setTipoBem(TipoBem.valueOf(valores[3].toString())); // alias tipoBem
      bem.setLocal(new Local()); // instancio um novo local e o associo ao bem
      bem.getLocal().setDescricao((String) valores[4]); // seto a descrição do local do bem

      return bem; // retorna o bem
   }
}

O método transformList é chamado somente uma vez, caso você queira fazer alguma operação sobre a listagem retornada pelo Hibernate. A operação mais importante, obviamente, está no método transformTuple. Ele é invocado para cada linha retornada na Query, devolve um Object e possui dois parâmetros: o primeiro é um Array de objetos com todos os valores retornados para cada linha da query; o outro são os alias de cada coluna.  É nesse método que vai acontecer todo o procedimento. No meu caso instancio um Bem, associo a um local e seto a descrição dele, retornando depois o bem recém alocado.

Aqui cabe uma observação: não é necessário usar os alias correspondendo aos atributos do objeto final quando se usa SQLQuery e o ResultTransform que você implementou. Não modifiquei a consulta apenas para não complicar.

Anúncios
  1. Nenhum comentário ainda.
  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: