AXOPEN

Hibernate 4 et les fonctions d’agrégat

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 requêtes avec Hibernate 4 ».

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. Vous passez en paramètre à celles-ci les champs concernés.

Exemple

Si je veux compter les commandes :

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(Long.class);
Root root = criteriaQuery.from(Commande.class);
criteriaQuery.select(builder.count(root));
TypedQuery typedQuery = entityManager.createQuery(criteriaQuery);
Long result = typedQuery.getSingleResult();

ou si je cherche le montant le plus élevé :

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(Double.class);
Root root = criteriaQuery.from(Commande.class);
criteriaQuery.select(builder.max(root.get(Commande_.total)));
TypedQuery typedQuery = entityManager.createQuery(criteriaQuery);
List result = typedQuery.getResultList();

ou encore si je veux connaître le panier moyen :

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(Double.class);
Root root = criteriaQuery.from(Commande.class);
criteriaQuery.select(builder.avg(root.get(Commande_.total)));
TypedQuery typedQuery = entityManager.createQuery(criteriaQuery);
List result = typedQuery.getResultList();

Attention ! N’oubliez pas de modifier le type de votre CriteriaQuery et de votre TypedQuery en fonction de ce que vous voulez ramener. 

Remarque : si votre clause SELECT contient un COUNT() et rien d’autre, et seulement dans ce cas là, vous pouvez appeler la fonction getSingleResult() à la place de getResultList(). Pourquoi pas le reste du temps ? Parce que getSingleResult() propage une exception lorsque la requête ramène un nombre de résultat différent de 1 (zéro compris). Or COUNT() ramène forcément un résultat puisque s’il ne trouve rien il renvoie 0, alors que SUM() par exemple est susceptible de retourner NULL.