Recentemente precisei criar um relatório específico para um projeto no qual há uma grande quantidade de filtros possíveis. Ao analisar esse cenário, eu e a equipe decidimos utilizar o Criteria do Hibernate por causa da facilidade de manipular dinamicamente os filtros. E, no meio da implementação, encontramos um problema no resultado da busca.
Vamos ao exemplo:
Numa lanchonete existem vários tipos de lanche. Cada lanche tem seus ingredientes. E, na minha busca, eu quero trazer só os lanches que possuem bacon.
Suponhamos que temos os registros a seguir:
[markdown]
“`
Lanche: X-Salada
–Ingredientes: Pão, carne, queijo e salada.
Lanche: X-Egg Bacon
–Ingredientes: Pão, carne, queijo, ovo e bacon.
Lanche: X-Bacon
–Ingredientes: Pão, carne, queijo e bacon.
“`
[/markdown]
Nossas classes ficariam assim:
[markdown]
“`
@Entity
public class Lanche {
@Id
private Long id;
private String nome;
private List ingredientes;
}
@Entity
public class Ingrediente {
@Id
private Long id;
private String nome;
}
“`
[/markdown]
Na nossa primeira tentativa de executar a busca, fizemos o seguinte código:
[markdown]
“`
Criteria criteria = session.getCurrentSession().createCriteria(Lanche.class);
criteria.createAlias(“ingredientes”, “in”, JoinType.LEFT_OUTER_JOIN);
criteria.add(Restrictions.eq(“in.nome”, “Bacon”));
criteria.list();
“`
[/markdown]
O resultado estava correto. Porém, cada lanche retornado continha somente bacon. E precisávamos de todos os ingredientes dos lanches. Retorno:
[markdown]
“`
Lanche: X-Egg Bacon
–Ingredientes: Bacon
Lanche: X-Bacon
–Ingredientes: Bacon
“`
[/markdown]
Vimos, então, que não daria certo buscar desta forma. Para solucionar o problema, utilizamos subquery do Criteria. Refatoramos o código e ficou assim:
[markdown]
“`
Criteria criteria = session.getCurrentSession().createCriteria(Lanche.class);
// Busca todos os lanches que possuem ingrediente bacon
DetachedCriteria lanches = DetachedCriteria.forClass(Lanche.class, “la”);
lanches.createAlias(“la.ingredientes”, “in”, JoinType.INNER_JOIN);
lanches.add(Restrictions.eq(“in.nome”, “Bacon”));
lanches.setProjection(Property.forName(“la.id”));
// Lista os lanches com base nos ids retornados da busca acima.
criteria.add(Property.forName(“id”).in(lanches));
criteria.list();
“`
[/markdown]
E o resultado:
[markdown]
“`
Lanche: X-Egg Bacon
–Ingredientes: Pão, carne, queijo, ovo e bacon.
Lanche: X-Bacon
–Ingredientes: Pão, carne, queijo e bacon.
“`
[/markdown]
[markdown]
—
[/markdown]
Gabriel Suaki – Software Engineer at redspark.
GitHub: GSuaki
Twitter: @gsuaki