268 votes

Comment faire une requête de limite dans JPQL ou HQL ?

Dans Hibernate 3, existe-t-il un moyen de faire l'équivalent de la limite MySQL suivante dans HQL ?

select * from a_table order by a_table_column desc limit 0, 20;

Je ne veux pas utiliser setMaxResults si possible. Cela était certainement possible dans l'ancienne version d'Hibernate/HQL, mais cela semble avoir disparu.

2 votes

J'utilise Hibernate-5.0.12 . N'est-il pas encore disponible ? Il serait vraiment lourd d'obtenir un million d'enregistrements et d'appliquer ensuite le filtre dessus setMaxResults par-dessus, comme l'a remarqué @Rachel dans la réponse de @skaffman.

336voto

skaffman Points 197885

Cela a été posté sur le forum Hibernate il y a quelques années, lorsqu'on lui a demandé pourquoi cela fonctionnait dans Hibernate 2 mais pas dans Hibernate 3 :

La limite était jamais une clause supportée dans HQL. Vous êtes censé utiliser setMaxResults().

Donc, si cela a fonctionné dans Hibernate 2, il semble que ce soit par coïncidence, plutôt qu'à dessein. I pensez à En effet, l'analyseur HQL d'Hibernate 2 remplaçait les parties de la requête qu'il reconnaissait comme HQL et laissait le reste tel quel, ce qui permettait d'introduire en douce du SQL natif. Hibernate 3, cependant, dispose d'un véritable analyseur AST HQL, et il est beaucoup moins indulgent.

Je pense Query.setMaxResults() est vraiment votre seule option.

1 votes

J'espérais qu'ils se rendraient compte que c'est ennuyeux. De plus, si vous regardez le code source, ils l'ont implémenté pour chaque base de données, et chaque base de données est différente. Oh et bien, c'est triste.

3 votes

Je dirais que l'approche d'Hibernate 3 est plus correcte. Votre utilisation d'Hibernate est censée être indépendante de la base de données, et vous devez donc faire ce genre de choses de manière abstraite.

6 votes

Je suis d'accord, mais la migration est un vrai calvaire quand les fonctionnalités sont abandonnées comme ça.

158voto

Jessu Points 669
 // SQL: SELECT * FROM table LIMIT start, maxRows;

Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);

6 votes

Je préfère celui-là parce que setFirstResult est réellement mentionné dans cette réponse alors qu'ici et ailleurs, ils disent simplement setMaxResults ceci et setMaxResults sans mentionner comment régler le décalage.

21voto

pjp Points 7012

Si vous ne voulez pas utiliser setMaxResults() sur le Query puis vous pourrez toujours revenir à l'utilisation du SQL normal.

46 votes

Ce n'est pas si excitant que ça.

9 votes

Je ne trouve pas HQL excitant non plus. Pourquoi ne pas écrire une vue sur votre serveur de base de données qui applique la limite et ensuite faire en sorte que HQL regarde cette vue :P

1 votes

C'est juste une de ces choses, alors que le SQL est beaucoup plus facile que le HQL pour chaque requête, la création de vues et l'écriture de SQL natif ont tendance à ne pas être si géniales pour le remaniement. J'essaie d'éviter cela quand je le peux. Le vrai problème est que j'ai mal écrit ma requête MySQL de toute façon et j'ai pensé que setMaxResults était bizarre. Ce n'était pas le cas.

5voto

Lluis Martinez Points 710

Si vous ne voulez pas utiliser setMaxResults, vous pouvez également utiliser Query.scroll au lieu de list, et récupérer les lignes que vous souhaitez. Utile pour la pagination par exemple.

0 votes

Merci, la réponse acceptée n'a pas résolu le problème pour moi, car setMaxResults() charge d'abord chaque enregistrement en mémoire, puis crée une sous-liste, ce qui, lorsqu'il y a des centaines de milliers d'enregistrements ou plus, fait planter le serveur, car il n'a plus de mémoire. Je pourrais cependant passer d'une requête typée JPA à une requête Hibernate par le biais de QueryImpl hibernateQuery = query.unwrap(QueryImpl.class) et ensuite je pourrais utiliser le scroll() comme vous l'avez suggéré.

0 votes

Au moins avec le dialecte Oracle, ce n'est pas vrai (Hibernate utilise la colonne virtuelle ROWNUM). Peut-être cela dépend-il du pilote. D'autres BD ont la fonction TOP.

0 votes

Ma requête utilise un joint fetch. Cela donne lieu à l'avertissement d'Hibernate "firstResult/maxResults specified with collection fetch ; applying in memory". Donc, avec une requête jointe, Hibernate charge la collection complète en mémoire. L'abandon de la jointure n'est pas possible pour des raisons de performances. Lorsque j'utilise ScrollableResults, j'ai plus de contrôle sur les enregistrements qui sont chargés en mémoire. Je ne peux pas charger tous les enregistrements avec un seul ScrollableResults, car cela entraîne également une saturation de la mémoire. J'expérimente le chargement de plusieurs pages avec différents ScrollableResults. Si cela ne fonctionne pas, j'utiliserai SQL.

1voto

Dilawar Points 31

String hql = "select userName from AccountInfo order by points desc 5";

Cela a fonctionné pour moi sans utiliser setmaxResults();

Il suffit de fournir la valeur maximale dans le dernier (dans ce cas 5) sans utiliser le mot-clé limit . :P

7 votes

Hm... je ne suis pas trop sûr de cela, [citation nécessaire] cela peut être un accident et pourrait soudainement cesser de fonctionner dans une nouvelle version d'hibernation.

4 votes

Veuillez vous référer au document officiel.

2 votes

Cela ne fonctionne pas pour moi dans Hibernate Version 5.2.12 Final

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X