1
resposta

@ManyToOne várias consultas

Ola pessoal, estou com um exemplo real e não sei como resolver. No sistema da empresa onde eu trabalho eu tenho uma entidade com vários relacionamentos @ManyToOne.

...
@ManyToOne
    @JoinColumns
    ({
        @JoinColumn(name = "EMPRESA", referencedColumnName = "EMPRESA", insertable = false, updatable = false),
        @JoinColumn(name = "NR_GUIA", referencedColumnName = "NR_GUIA", insertable = false, updatable = false)
    })
    private SaGuia saGuia;

    @ManyToOne
    @JoinColumns
    ({
        @JoinColumn(name = "EMPRESA",     referencedColumnName = "EMPRESA",     insertable = false, updatable = false),
        @JoinColumn(name = "NR_CONTRATO", referencedColumnName = "NR_CONTRATO", insertable = false, updatable = false),
        @JoinColumn(name = "PLANO",       referencedColumnName = "PLANO",       insertable = false, updatable = false),
        @JoinColumn(name = "ID_USUARIO",  referencedColumnName = "ID_USUARIO",  insertable = false, updatable = false),
        @JoinColumn(name = "CONTROLE",    referencedColumnName = "CONTROLE",    insertable = false, updatable = false)
    })
    private SaPlanoUsuario saPlanoUsuario;

    @ManyToOne
    @JoinColumns
    ({
        @JoinColumn(name = "ID_PRESTADOR",  referencedColumnName = "ID_PRESTADOR",  insertable = false, updatable = false),
        @JoinColumn(name = "ID_LOCALIDADE", referencedColumnName = "ID_LOCALIDADE", insertable = false, updatable = false)
    })
    private SaPrestadorLocalidade saPrestadorLocalidade;

    @ManyToOne
    @JoinColumns
    ({
        @JoinColumn(name = "ID_SOLICITANTE",       referencedColumnName = "ID_PRESTADOR" ),
        @JoinColumn(name = "ID_LOCAL_SOLICITANTE", referencedColumnName = "ID_LOCALIDADE")
    })
    private SaPrestadorLocalidade saPrestadorLocalidadeSolicitante;

    @ManyToOne
    @JoinColumns
    ({
        @JoinColumn(name = "ID_ANESTESISTA",        referencedColumnName = "ID_PRESTADOR" ),
        @JoinColumn(name = "ID_PERFIL_ANESTESISTA", referencedColumnName = "ID_LOCALIDADE")
    })
    private SaPrestadorLocalidade saPrestadorLocalidadeAnestesista;

    @ManyToOne
    @JoinColumns
    ({
        @JoinColumn(name = "EMPRESA",      referencedColumnName = "EMPRESA",      insertable = false, updatable = false),
        @JoinColumn(name = "NR_PROTOCOLO", referencedColumnName = "NR_PROTOCOLO", insertable = false, updatable = false)
    })
    private SaPrestadorProtocolo saPrestadorProtocolo;

    @ManyToOne
    @JoinColumn(name = "SITUACAO_ATENDIMENTO", referencedColumnName = "SITUACAO_ATENDIMENTO")
    private SaSituacaoAtendimento situacaoAtendimento;

    @ManyToOne
    @JoinColumns
    ({
        @JoinColumn(name = "ID_TABELA_REF", referencedColumnName = "ID_TABELA_REF"),
        @JoinColumn(name = "PROCEDIMENTO",  referencedColumnName = "PROCEDIMENTO" )
    })
    private SaTabelaRefProcedimento saTabelaRefProcedimento;

    @ManyToOne
    @JoinColumn(name = "TP_ATENDIMENTO", referencedColumnName = "TP_ATENDIMENTO")
    private SaTipoAtendimento tpAtendimento;

    @ManyToOne
    @JoinColumn(name = "TP_SAIDA", referencedColumnName = "TP_SAIDA")
    private SaTipoSaida tpSaida;
...

Aqui está o trecho do meu CriteriaBuilder

...
CriteriaBuilder criteriaBuilder = this.getEntityManager().getCriteriaBuilder();
        CriteriaQuery<SaProtocoloSadt> query = criteriaBuilder.createQuery(SaProtocoloSadt.class);
        Root<SaProtocoloSadt> root = query.from(SaProtocoloSadt.class);

        Join<SaProtocoloSadt, SaPrestadorProtocolo> prestadorProtocolo = root.join("saPrestadorProtocolo", JoinType.LEFT);

        List<Predicate> predicates = new ArrayList<>();

        if (entidade.getSaPrestadorProtocolo() != null && entidade.getSaPrestadorProtocolo().getId() != null)
        {
            Predicate protocolo = criteriaBuilder.equal(prestadorProtocolo, entidade.getSaPrestadorProtocolo());
            predicates.add(protocolo);
        }

        query.where((Predicate[]) predicates.toArray(new Predicate[0]));
        TypedQuery<SaProtocoloSadt> typedQuery = this.getEntityManager().createQuery(query);

        return typedQuery.getResultList();
...

Esse relacionamento eu sei que por padrão e do tipo EAGER. O que faz que quando eu pesquiso ele faça diversas queries para cada relacionamento.

Com isso a consulta fica extremamente lenta porque tem 12 relacionamentos, ainda mais se tiver muitos elementos que devem ser retornados;

Atualmente, para "contornar" esse problema de lentidão, foi feito uma nativeQuery (onde ela pesquisa todos os elementos da tabela) que retorna os valores, onde esses valores posteriormente são atribuídos ao Objeto específico:

ArrayList<MinhaEntidade> lista = new ArrayList<MinhaEntidade>();
for(Object[] e : (Collection<Object[]>) q.getResultList())
{
...
o = new MinhaEntidade(...);
o.setParametro(e[0])
o.setParametro(e[1])
...
lista.add(o);
...
}

Dessa forma, uma lista de 700 objeto por exemplo é feita em poucos segundos. Estou tentando usar joins para o CriteriaBuider, mas não estou sabendo utilizar ele.

1 resposta

Acho que o melhor, sinceramente, é manter a nativeQuery... a criteriaBuilder é muito complicada, de verdade... acaba com um código que ninguém entende... de todo jeito, você precisaria buscar o jeito de fazer os fetch join na criteria, para ele carregar os relacionamentos...