Wednesday, August 26, 2015

Fazendo fetch via Criteria da JPA sem Metamodel Class

Outra dica relacionada a API de Criteria da JPA 2. A questão agora é: como realizar uma consulta flexível, com critérios variados, carregar os dados de uma entidade complementar (fetch) sem usar a classe gerada via Metamodel.

Como exemplo vou usar uma estrutura bem simples, duas entidades: Categoria e Mercadoria. O clássico relacionamento One-To-Many, sendo que uma Categoria possui várias Mercadoria(s). Nesse caso, a Categoria é a entidade raiz para construção da consulta.

O cenário é: gerar um relatório com as Categorias cuja as Mercadorias tenham preço entre R$ 500,00 e R$ 899,00. Além das informações das Categorias, o relatório também deve exibir as informações das Mercadorias que se enquadram nessa faixa de valores.

O pedaço de código a seguir é uma alternativa para implementar essa funcionalidade:
public final class CategoriaSpecification {
  
  public static Specification<Categoria> byPrecoComMercadoria(BigDecimal precoDe, 
      BigDecimal precoAte) {
    return new Specification<Categoria>() {
      @Override
      public Predicate toPredicate(Root<Categoria> root,
          CriteriaQuery<?> query, CriteriaBuilder builder) {
        FetchParent<Categoria, Mercadoria> fetch = root.fetch("mercadorias");
        Join<Categoria, Mercadoria> join = 
          (Join<Categoria, Mercadoria>) fetch; //truque

        return builder.between(join.get("preco"),
          precoDe, precoAte);
      }
    };
  }
  ...
}

O "truque" é usar o método fetch em root, mas converter a visão do objeto para Join. Os tipos Join e Fetch tem em comum a interface FetchParent. Com Join é possível definir predicados na construção da query. Note que nesse exemplo, eu uso o componente de Specification do Spring Data JPA.

www.yaw.com.br

No comments: