Estou tendo alguns problemas em utilizar EntityGraph com Criteria API.
No retorno da consulta, continuam sendo executados vários selects, evidenciando o problema do N+1.
Seguem os arquivos:
Produto.java
package br.com.caelum.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.validator.constraints.NotEmpty;
@DynamicUpdate
@NamedEntityGraphs({
@NamedEntityGraph(name = "ProdutoCategoria", attributeNodes = {
@NamedAttributeNode("categorias")})
})
@Entity
public class Produto {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@NotEmpty
private String nome;
@NotEmpty
private String linkDaFoto;
@NotEmpty
@Column(columnDefinition="TEXT")
private String descricao;
@Min(20)
private double preco;
@Valid
@ManyToOne
private Loja loja;
@ManyToMany
@JoinTable(name = "CATEGORIA_PRODUTO")
private List<Categoria> categorias = new ArrayList<>();
public String getDescricao() {
return descricao;
}
public void setDescricao(String descricao) {
this.descricao = descricao;
}
//método auxiliar para associar categorias com o produto
//se funcionar apos ter definido o relacionamento entre produto e categoria
public void adicionarCategorias(Categoria... categorias) {
for (Categoria categoria : categorias) {
this.categorias.add(categoria);
}
}
public String getLinkDaFoto() {
return linkDaFoto;
}
public double getPreco() {
return preco;
}
public void setPreco(double preco) {
this.preco = preco;
}
public void setLinkDaFoto(String linkDaFoto) {
this.linkDaFoto = linkDaFoto;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public void setLoja(Loja loja) {
this.loja = loja;
}
public Loja getLoja() {
return loja;
}
public List<Categoria> getCategorias() {
return categorias;
}
public void setCategorias(List<Categoria> categorias) {
this.categorias = categorias;
}
}
Meu método getProdutos
public List<Produto> getProdutos(String nome, Integer categoriaId, Integer lojaId) {
EntityGraph entityGraph = em.getEntityGraph("ProdutoCategoria");
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery <Produto> query = criteriaBuilder.createQuery(Produto.class);
Root <Produto> root = query.from(Produto.class);
query.distinct(true);
Path <String> nomePath = root.<String>get("nome");
Path <Integer> categoriaPath = root.join("categorias").<Integer>get("id");
Path <Integer> lojaPath = root.<Loja>get("loja").<Integer>get("id");
Predicate conjuncao = criteriaBuilder.conjunction();
if(!nome.isEmpty()) {
conjuncao = criteriaBuilder.and(criteriaBuilder.like(nomePath, "%"+nome+"%"));
}
if(categoriaId != null) {
conjuncao = criteriaBuilder.and(conjuncao, criteriaBuilder.equal(categoriaPath, categoriaId));
}
if(lojaId != null) {
conjuncao = criteriaBuilder.and(conjuncao, criteriaBuilder.equal(lojaPath, lojaId));
}
TypedQuery<Produto> typedQuery = em.createQuery(query.where(conjuncao)).setHint("javax.persistence.loadgraph", entityGraph);
return typedQuery.getResultList();
}
Acredito que o problema esteja na linha, "Path categoriaPath = root.join("categorias").get("id");", porém preciso do categoriaPath para fazer o filtro por categoria. Como poderia resolver isso?
Abraços.