Dans cet article


Offres d'emploi

Tags

La clause GROUP BY en Hibernate 4

La clause GROUP BY en Hibernate 4

Comment utiliser la clause SQL GROUP BY avec Hibernate 4 ?

Rappel théorique

En SQL, lorsqu’une requête possède la clause GROUP BY, les champs mentionnés dans la clause SELECT ne peuvent être que :

  • une colonne sur laquelle porte le GROUP BY ;
  • une fonction d’agrégat (qui, elle, peut porter sur n’importe quelle colonne).

En clair, je ne peux pas mentionner dans mon SELECT une colonne sur laquelle je ne groupe pas. La plupart du temps ce genre de requête n’a aucun sens, mais il arrive que ce soit moins évident. Dans ces cas-là, il faut s’en remettre à ses souvenirs de SQL classique.

Pourquoi le préciser ici ? Parce qu’au même titre que MySQL est ultra-laxiste sur la syntaxe des requêtes utilisant la clause GROUP BY, Hibernate ne verra pas d’inconvénient à générer des requêtes qui n’ont pas de sens. Mais tous les SGBD ne sont pas comme ça, et s’il vous arrivait de passer d’un MySQL à Oracle, mieux vaut pour vous que vous n’ayez pas à réécrire toutes les requêtes de votre application… car Oracle, lui, ne plaisante pas avec les GROUP BY.

Le principe

Si vous savez faire une requête simple avec Hibernate 4, l’utilisation du GROUP BY va vous paraître un jeu d’enfant. Il suffit d’utiliser la méthode groupBy() de votre CriteriaQuery, à laquelle vous passez en paramètre le champ sur lequel vous voulez grouper.

Exemple : la liste des numéros de commande groupés par eux-même :

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<
String> criteriaQuery = builder.createQuery(String.class);
Root<
Commande> root = criteriaQuery.from(Commande.class);
criteriaQuery.select(root.get(Commande_.numero));
criteriaQuery.groupBy(root.get(Commande_.numero));
TypedQuery<
String> typedQuery = entityManager.createQuery(criteriaQuery);
List<
String> result = typedQuery.getResultList();

C’est seulement pour le principe car cette requête n’a aucun intérêt. En général on cherche une information qui n’est pas spécifiquement dans la colonne du GROUP BY.

En pratique

Un exemple plus pertinent : le nombre de commandes par jour :

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<
Tuple> criteriaQuery = builder.createQuery(Tuple.class);
Root<
Commande> root = criteriaQuery.from(Commande.class);
criteriaQuery.multiselect(root.get(Commande_.date), builder.count(root));
criteriaQuery.groupBy(root.get(Commande_.date));
TypedQuery<
Tuple> typedQuery = entityManager.createQuery(criteriaQuery);
List<
Tuple> result = typedQuery.getResultList();

On a ici un exemple certes un peu complexe mais plus intéressant qui mêle l’utilisation du GROUP BY, de la fonction d’agrégat COUNT() et du multiselect() (si vous n’êtes pas familier avec cette notion, voyez l’article qui lui est dédié).

Remarquez que vous pouvez spécifier plusieurs colonnes de regroupement. Exemple : la liste des commandes groupées par jour et par fournisseur :

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<
Tuple> criteriaQuery = builder.createQuery(Tuple.class);
Root<
Commande> root = criteriaQuery.from(Commande.class);
criteriaQuery.multiselect(root.get(Commande_.date), root.get(Commande_.fournisseur), builder.count(root));
List<
Expression<?>> groupList = new ArrayList();
groupList.add(root.get(Commande_.date));
groupList.add(root.get(Commande_.fournisseur));
criteriaQuery.groupBy(groupList);
TypedQuery<
Tuple> typedQuery = entityManager.createQuery(criteriaQuery);
List<
Tuple> result = typedQuery.getResultList();

L'équipe AXOPEN

Voir aussi les articles suivants

Hibernate 4 et les fonctions d&rsquo;agrégat

Hibernate 4 et les fonctions d’agrégat

Le 26/11/2013 par Florent Tripier

En SQL, les fonctions d’agrégat sont les fonctions COUNT(), SUM(), MIN(), MAX() et AVG(). Comment réaliser des requêtes avec de telles fonctions dans la clause SELECT en Hibernate 4 ? Théorie Si vous n’êtes pas familier avec Hibernate 4, reportez-vous préalablement à l’article  ». Les fonctions d’agrégats sont fournies par le CriteriaBuilder. Il suffit donc de passer en paramètre à votre fonction select() non pas un champ ou un Root mais la fonction d’agrégat.
Lire l'article

Le multiselect avec Hibernate 4

Le multiselect avec Hibernate 4

Le 05/11/2013 par Florent Tripier

Nous avons vu dans l’article « Les requêtes avec Hibernate 4 » comment réaliser une requête ramenant soit un champ soit tous les champs (SELECT *). Voyons à présent comment ramener plusieurs champs mais pas tous. Le code côté Hibernate Pour ce faire, nous avons recours à la fonction multiselect() de la classe CriteriaQuery. Cette fonction prend en paramètres soit une List de champs, soit n paramètres représentant des champs ou des fonctions.
Lire l'article

Les requêtes avec Hibernate 4

Les requêtes avec Hibernate 4

Le 02/10/2013 par Florent Tripier

Hibernate 4 propose une syntaxe structurée qui permet d’exploiter la plupart des fonctionnalités du SQL. Cette syntaxe s’articule autour de quelques classes clés. Les classes clés pour construire une requête EntityManager L’EntityManager vous donne accès à votre PersistenceUnit, c’est-à-dire à votre base de données. C’est donc à partir de lui que seront construits tous les objets suivants. La configuration de la PersistenceUnit fera l’objet d’un autre article. CriteriaBuilder Le CriteriaBuilder est généré par l’EntityManager.
Lire l'article