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