Pergunta

O implementando-result-paginação in- hibernate-recebendo linhas-Total-número-de- questão gatilho outra pergunta para mim, sobre alguma preocupação implementação :

Agora você sabe que tem de reutilizar parte da consulta HQL para fazer a contagem, como reutilizar de forma eficiente?

As diferenças entre as duas consultas HQL são:

  1. a seleção é count(?), em vez do pojo ou propriedade (ou lista de)
  2. as buscas não deve acontecer, por isso algumas tabelas não devem ser unidos
  3. o order by deve desaparecer

Há outras diferenças?

Você tem codificação de melhores práticas para alcançar este reutilização eficiente (preocupações: esforço, claridade, desempenho)?

Exemplo para uma consulta HQL simples:

    select       a     from A a join fetch a.b b where a.id=66 order by a.name
    select count(a.id) from A a                  where a.id=66

ATUALIZADO

Recebi respostas em:

  • usando Critérios (mas usar HQL principalmente)
  • manipular a cadeia consulta (mas todos concordam parece complicado e não muito seguro)
  • envolvendo a consulta , contando com otimização de banco de dados (mas há uma sensação de que este não é seguro)

Eu estava esperando que alguém iria dar opções ao longo outro caminho, mais relacionadas com concatenação de String.
nós poderíamos construir ambas as consultas HQL usando partes comuns ?

Foi útil?

Solução

questão Nice. Aqui está o que eu fiz no passado (muitas coisas que você já mencionados):

  1. Verifique se SELECT cláusula está presente.
    1. Se não for, adicione select count(*)
    2. Caso contrário, verifique se ele tem ou funções de agregação DISTINTAS na mesma. Se você estiver usando ANTLR para analisar a sua consulta, é possível trabalhar em torno daqueles mas está bastante envolvido. Você é provável melhor fora apenas envolvendo a coisa toda com select count(*) from ().
  2. Remover fetch all properties
  3. Remover fetch de junta se você estiver análise HQL como string. Se você está analisando verdadeiramente a consulta com ANTLR você pode remover left join inteiramente; É um pouco confuso para verificar todas as referências possíveis.
  4. Remover order by
  5. Dependendo do que você fez no 1.2 você precisará remover / ajustar group by / having.

O acima se aplica a HQL, naturalmente. Para consultas critérios que você está bastante limitado com o que você pode fazer, porque não se presta à manipulação facilmente. Se você estiver usando algum tipo de uma camada de invólucro em cima de critérios, você vai acabar com o equivalente a (limitado) subconjunto de ANTLR resultados análise e poderia se aplicar mais do que precede, nesse caso.

Uma vez que você normalmente segurar a compensação de sua página atual e a contagem total, eu costumo executar a consulta real com determinado limite / compensado primeiro e único executar a consulta count(*) se o número de resultados de retorno é mais ou igual ao limite e offset é zero (em todos os outros casos que eu quer executar o count(*) antes ou eu tenho todos os resultados de volta de qualquer maneira). Esta é uma abordagem otimista com relação a modificações concorrentes, é claro.

Atualizar (em HQL-montagem mão)

Eu particularmente não gosto dessa abordagem. Quando mapeado como consulta nomeada, HQL tem a vantagem de verificação de erros em tempo de compilação (bem, o tempo de execução tecnicamente, porque SessionFactory tem que ser construído, embora que geralmente é feito durante a integração testes de qualquer maneira). Quando gerado em tempo de execução ele falhar em tempo de execução :-) Fazer otimizações de desempenho não é exatamente fácil.

O mesmo raciocínio se aplica a critérios, é claro, mas é um pouco mais difícil de estragar devido a API bem definida em oposição a concatenação. Construção de duas consultas HQL em paralelo (paginados um e um "contagem global") também leva a duplicação de código (e potencialmente mais bugs) ou obriga a escrever algum tipo de camada de invólucro em cima para fazer isso por você. Ambas as formas estão longe do ideal. E se você precisar fazer isso a partir do código do cliente (como em mais API), o problema fica ainda pior.

Eu realmente ponderado bastante pouco sobre esta questão. Pesquisar API de Hibernate-Generic-DAO parece ser um compromisso razoável; há mais detalhes em minha resposta para a questão ligada acima.

Outras dicas

Você tentou fazer suas intenções claras para Hibernate, definindo uma projeção em seu SQL (?) Critérios? Eu estive na sua maioria usando critérios, então eu não sei como aplicável este é o seu caso, mas eu tenho usado

getSession().createCriteria(persistentClass).
setProjection(Projections.rowCount()).uniqueResult()

e deixando figura Hibernate o cache / reutilização / stuff inteligente por si só .. Realmente não sei quanta coisa inteligente que ele realmente faz embora .. Qualquer um cuidado para comentar sobre isso?

Bem, eu não tenho certeza que esta é uma melhor prática, mas é o meu práticas:)

Se eu tiver como consulta algo como:

select A.f1,A.f2,A.f3 from A, B where A.f2=B.f2 order by A.f1, B.f3

E eu só quero saber quantos resultados obterá, eu executar:

select count(*) from ( select A.f1, ... order by A.f1, B.f3 )

E, em seguida, obter o resultado como um inteiro, sem resultados de mapeamento em um POJO.

Analise sua consulta para remover algumas peças, como 'ordem por' é muito complicado. Um bom RDBMS irá otimizar sua consulta para você.

Boa pergunta.

Em uma situação à mão livre HQL eu usaria algo assim, mas isso não é reutilizável, pois é muito específica para as entidades dadas

Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();

Faça isso uma vez e ajustar o número inicial de acordo até que você página através de.

Para os critérios que eu uso uma amostra como esta

final Criteria criteria = session.createCriteria(clazz);  
            List<Criterion> restrictions = factory.assemble(command.getFilter());
            for (Criterion restriction : restrictions)
                criteria.add(restriction);
            criteria.add(Restrictions.conjunction());
            if(this.projections != null)
                criteria.setProjection(factory.loadProjections(this.projections));
            criteria.addOrder(command.getDir().equals("ASC")?Order.asc(command.getSort()):Order.desc(command.getSort()));
            ScrollableResults scrollable = criteria.scroll(ScrollMode.SCROLL_INSENSITIVE);
            if(scrollable.last()){//returns true if there is a resultset
                genericDTO.setTotalCount(scrollable.getRowNumber() + 1);
                criteria.setFirstResult(command.getStart())
                        .setMaxResults(command.getLimit());
                genericDTO.setLineItems(Collections.unmodifiableList(criteria.list()));
            }
            scrollable.close();
            return genericDTO;

Mas isso não a contar cada vez chamando ScrollableResults:last().

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top