Hibernate Criteria – Restrições em listas com subquery

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

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>