Possuo um objeto A que possui uma collection de objetos B
Um determinado objeto A, possui quase 40.000 objetos B, e tenho uma tela que lista todos ops objetos B. O grande problema é que 40.000 objetos selecionados na tela acaba dando OutOfMemory.
O mais correto seria fazer uma paginação, onde selecionaria apenas 50 objetos B de cada vez.
Pergunta: Como posso fazer isso, se ao executar a.getBs(), o Hibernate já me retorna tudo de uma vez ? Com query nativa, eu faria os selects em lote e tudo se resolveria, mas não gostaria de criar essas consultas nativas.
StringBuildersbQuery=newStringBuilder();Queryquery=null;sbQuery.append("select count(*) from sua_classe_B");//getSession, retorna a sessão do hibernate//Neste caso estou considerando que vc ja a possuiquery=getSession().createQuery(sbQuery.toString());Longcount=(Long)query.uniqueResult();//O numero count, é o numero de registros que vc possui, para que vc possa fazer a paginação.
Paginado o seu resultado:
Queryquery=null;intmaxRecords=10;sbQuery.append("from sua_classe_B");/*Esta linha indica a partir de qual registo sua lista sera formadaComo maxRecords == 10, estou pegando o que seria a pagina 2.onde o meu primeiro registro é 1 * 10 = 10 A primeira pagina seria 0*10 = 0*/query.setFirstResult(1*maxRecords);/*Esta linha indica quantos registros serão recuperados a partir do primeiro*/query.setMaxResults(maxRecords);list=query.list();
Qualquer duvida poste ai...
A
andre_a_s
Sim, via HQL é possivel, mas seria possivel SEM HQL ?
G
garcia-jj
O que seria sem HQL? Com criteria?
R
roger_rf
Não sei se é exatamente isso que você procura, mas talvez a técnica de “batch fetching” seja útil:
Não necessariamente.
Por exemplo, hoje, quando executo a.getBs(), ele me traz todos os objetos B dentro de A. Isso não é feito via HQL, é feito automático pelo mapeamento.
Estou procurando uma alternativa para trazer os mesmos objetos B, executando por exemplo getBs(1, 50), para pegar do primeiro ao quinquagésimo.
Minha duvida é, este tipo de coisa só é possivel via HQL/Criteria, ou é possivel fazer via mapeamento, como o link que roger_rf passou ?
M
marcelo.martins
Ola,
O mapeamento do objeto A ou B individualmente, vc pode fazer da forma de exemplifiquei ou por Criteria...
Se quizer te mostro como fazer com Criteria,
Então neste cenario, acredito que não tenha como vc paginar a lista B,
Posso estar dizendo besteira, mas pense bem:
Como vc ia estar limitando o numero de registros dentro desta lista?
No minimo o hibernate teria que manter a sessão aberta e ficar gerenciando sua interação em tempo de execução...
Não sei se tem como vc fazer isso...
O que vc pode estar fazendo é remover o objeto filho, e tratalo de forma independente.
Porem ja te adiantando, se vc fizer por exemplo um combo com sujestion, ficara pesado tambem.
Mas se a sua consulta estiver muito pesada com o objeto filho dentro de A, vc pode remove-lo...(dependendo de como estão suas telas e relacionamentos)
G
garcia-jj
Pelo que entendi você quer fazer paginação pelo mapeamento one-to-many da entidade, e isso não é possível.
Na verdade eu sou bem contra fazer mapeamentos bidirecionais to tipo one-to-many e many-to-one. No seu caso A possui muitos B, então o correto é A não possuir a coleção de B, mas B possuir a referencia para A. Não gosto de usar A.getB, e um dos motivos é de você carregar todos os registros da base sem distinção.
O mais correto, na minha opinião, é você fazer uma chamada via HQL ou criteria para trazer todos os B que são filhos de A com seus critérios de paginação.
T
Tecnoage
eu tb estava algum tempo atrás procurando uma resposta para isso, acabei construindo via query mesmo…
T
thiago.correa
Foi por coincidência que eu achei isso na documentação do hibernate, veja se adianta
funcionalmente é desse modo que se faz, porém o que procurei ( e ainda procuro ) é algum mecanismo que faça para um relacionamento 1:N lazy, por exemplo a paginação automática, sem a necessidade de criar uma hql ou uma critéria para isso.
G
garcia-jj
Se você ler meu comentário verá que realmente usando o relacionamento não há como fazer paginado. E se você procurar na community manuals do hibernate (não sei se no site do jboss novo tem isso) há um post que fala exatamente do quão ruim é você ter bidirecionais e sair usando algo como:
Sendo que o correto é você ter apenas o relacionamento de Debit.customer, e não ambos Debit.customer e Customer.debits.
A forma mais correta de você paginar é usar o que o Thiago indicou no post dele. Formula mágina para paginação você não irá encontrar.
T
Tecnoage
Se você ler meu comentário verá que realmente usando o relacionamento não há como fazer paginado. E se você procurar na community manuals do hibernate (não sei se no site do jboss novo tem isso) há um post que fala exatamente do quão ruim é você ter bidirecionais e sair usando algo como:
Sendo que o correto é você ter apenas o relacionamento de Debit.customer, e não ambos Debit.customer e Customer.debits.
A forma mais correta de você paginar é usar o que o Thiago indicou no post dele. Formula mágina para paginação você não irá encontrar.
Não estamos falando necessariamente em relacionamentos bidirecionais, muito pelo contrário.
A meu ver essa paginação AINDA é burra, força meu código “cliente” a fazer iterações baseadas em limites da query. Em termos de código LIMPO, essa é a pior solução, mas até onde encontrei é a única.
Isso geralmente resolve os problemas de sistemas onde ALGUMAS queries podem “explodir” a memória, mas torna sistemas com monstruosas quantidades de informações labirintos lógicos.
E esse é somente uma das limitações do hibernate. Existem uma série de outras, como a não inclusão de tipos PK (simples ou compostas) e qualquer relacionamento em queries do tipo example, por exemplo…