1
resposta

Queries Planejadas com Criteria API - PARTE 2

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.

1 resposta

colocando como eager deve resolver:

criteria.setFetchMode("categorias",  FetchMode.EAGER);