Requêtes de critères JPA

1. Vue d'ensemble

Dans ce didacticiel, nous aborderons une fonctionnalité JPA très utile: les requêtes de critères.

Cela nous permet non seulement d'écrire des requêtes sans faire de SQL brut, mais nous donne également un contrôle orienté objet sur les requêtes, qui est l'une des principales fonctionnalités d'Hibernate. L'API Criteria nous permet de créer un objet de requête de critères par programmation, dans lequel nous pouvons appliquer différents types de règles de filtrage et de conditions logiques.

Depuis Hibernate 5.2, l'API Hibernate Criteria est obsolète et le nouveau développement se concentre sur l'API JPA Criteria. Nous allons explorer comment utiliser Hibernate et JPA pour créer des requêtes de critères.

2. Dépendances de Maven

Pour illustrer l'API, nous utiliserons l'implémentation JPA de référence - Hibernate.

Pour utiliser Hibernate, assurez-vous d'ajouter la dernière version de celui-ci à votre fichier pom.xml :

 org.hibernate hibernate-core 5.3.2.Final 

La dernière version d'Hibernate peut être trouvée ici.

3. Exemple simple utilisant des critères

Commençons par regarder comment récupérer des données à l'aide de requêtes Criteria. Nous verrons comment obtenir toutes les instances d'une classe particulière à partir de la base de données.

Nous avons une classe Item qui représente le tuple «ITEM» dans la base de données:

public class Item implements Serializable { private Integer itemId; private String itemName; private String itemDescription; private Integer itemPrice; // standard setters and getters }

Regardons une simple requête de critères qui récupérera toutes les lignes de « ITEM» de la base de données:

Session session = HibernateUtil.getHibernateSession(); CriteriaBuilder cb = session.getCriteriaBuilder(); CriteriaQuery cr = cb.createQuery(Item.class); Root root = cr.from(Item.class); cr.select(root); Query query = session.createQuery(cr); List results = query.getResultList();

La requête ci-dessus est une simple démonstration de la façon d'obtenir tous les éléments. Voyons ce qui a été fait, étape par étape:

  1. Créer une instance de Session à partir de l' objet SessionFactory
  2. Créez une instance de C riteriaBuilder en appelant la méthode getCriteriaBuilder ()
  3. Créez une instance de CriteriaQuery en appelant la méthode CriteriaBuilder createQuery ()
  4. Créer une instance de la requête en appelant la session CreateQuery () méthode
  5. Appelez la méthode getResultList () de l' objet de requête qui nous donne les résultats

Maintenant que nous avons couvert les bases, passons à certaines des fonctionnalités de la requête de critères:

3.1. Utilisation d' expressions

Le CriteriaBuilder peut être utilisé pour restreindre les résultats des requêtes en fonction de conditions spécifiques. En utilisant la méthode CriteriaQuery where () et en fournissant des expressions créées par CriteriaBuilder.

Voici quelques exemples d' expressions couramment utilisées :

Pour obtenir des articles d'un prix supérieur à 1000:

cr.select(root).where(cb.gt(root.get("itemPrice"), 1000));

Ensuite, obtenir des articles dont le prix itemPrix est inférieur à 1000:

cr.select(root).where(cb.lt(root.get("itemPrice"), 1000));

Les éléments ayant itemNames contiennent Chair :

cr.select(root).where(cb.like(root.get("itemName"), "%chair%"));

Enregistrements ayant un prix compris entre 100 et 200:

cr.select(root).where(cb.between(root.get("itemPrice"), 100, 200));

Pour vérifier si la propriété donnée est nulle:

cr.select(root).where(cb.isNull(root.get("itemDescription")));

Pour vérifier si la propriété donnée n'est pas nulle:

cr.select(root).where(cb.isNotNull(root.get("itemDescription")));

Vous pouvez également utiliser les méthodes isEmpty () et isNotEmpty () pour tester si une liste dans une classe est vide ou non.

Maintenant, inévitablement, la question se pose de savoir si nous pouvons combiner deux ou plusieurs des comparaisons ci-dessus ou non. La réponse est, bien sûr, oui - l'API Criteria nous permet d'enchaîner facilement des expressions :

Predicate[] predicates = new Predicate[2]; predicates[0] = cb.isNull(root.get("itemDescription")); predicates[1] = cb.like(root.get("itemName"), "chair%"); cr.select(root).where(predicates);

Pour ajouter deux expressions avec des opérations logiques:

Predicate greaterThanPrice = cb.gt(root.get("itemPrice"), 1000); Predicate chairItems = cb.like(root.get("itemName"), "Chair%");

Éléments avec les conditions définies ci-dessus jointes à Logical OR :

cr.select(root).where(cb.or(greaterThanPrice, chairItems));

Pour obtenir des éléments correspondant aux conditions définies ci-dessus jointes avec ET logique :

cr.select(root).where(cb.and(greaterThanPrice, chairItems));

3.2. Tri

Maintenant que nous connaissons l'utilisation de base de Criteria , jetons un coup d'œil aux fonctionnalités de tri de Criteria .

Dans l'exemple suivant, nous classons la liste dans l'ordre croissant du nom, puis dans l'ordre décroissant du prix:

cr.orderBy( cb.asc(root.get("itemName")), cb.desc(root.get("itemPrice")));

Dans la section suivante, nous verrons comment faire des fonctions d'agrégation.

3.3. Projections, agrégats et fonctions de regroupement

Jusqu'à présent, nous avons couvert la plupart des sujets de base. Voyons maintenant les différentes fonctions d'agrégation:

Obtenez le nombre de lignes:

CriteriaQuery cr = cb.createQuery(Long.class); Root root = cr.from(Item.class); cr.select(cb.count(root)); Query query = session.createQuery(cr); List itemProjected = query.getResultList();

Voici un exemple de fonctions d'agrégation:

Fonction d' agrégation pour la moyenne :

CriteriaQuery cr = cb.createQuery(Double.class); Root root = cr.from(Item.class); cr.select(cb.avg(root.get("itemPrice"))); Query query = session.createQuery(cr); List avgItemPriceList = query.getResultList();

Les autres méthodes d'agrégation utiles disponibles sont sum () , max () , min () , count () etc.

3.4. CriteriaUpdate

À partir de JPA 2.1, il est possible d'effectuer des mises à jour de base de données à l'aide de l' API Criteria .

CriteriaUpdate has a set() method that can used to provide new values for database records:

CriteriaUpdate criteriaUpdate = cb.createCriteriaUpdate(Item.class); Root root = criteriaUpdate.from(Item.class); criteriaUpdate.set("itemPrice", newPrice); criteriaUpdate.where(cb.equal(root.get("itemPrice"), oldPrice)); Transaction transaction = session.beginTransaction(); session.createQuery(criteriaUpdate).executeUpdate(); transaction.commit();

In the above snippet, we create an instance of CriteriaUpdate from the CriteriaBuilder and use its set() method to provide new values for the itemPrice. To update multiple properties, we just need to call the set() method multiple times.

3.5. CriteriaDelete

CriteriaDelete, as its name implies, enables a delete operation using the Criteria API. All we need is to create an instance of CriteriaDelete and use the where() method to apply restrictions:

CriteriaDelete criteriaDelete = cb.createCriteriaDelete(Item.class); Root root = criteriaDelete.from(Item.class); criteriaDelete.where(cb.greaterThan(root.get("itemPrice"), targetPrice)); Transaction transaction = session.beginTransaction(); session.createQuery(criteriaDelete).executeUpdate(); transaction.commit();

4. Advantage Over HQL

In the previous sections we've covered how to use Criteria Queries.

Clearly, the main and most hard-hitting advantage of Criteria queries over HQL is the nice, clean, Object Oriented API.

We can simply write more flexible, dynamic queries compared to plain HQL. The logic can be refactored with the IDE and has all the type-safety benefits of the Java language itself.

There are of course some disadvantages as well, especially around more complex joins.

So, generally speaking, we'll have to use the best tool for the job – that can be the Criteria API in most cases, but there are definitely cases where we'll have to go lower level.

5. Conclusion

In this article, we focused on the basics of Criteria Queries in Hibernate and JPA, and also on some of the advanced features of the API.

Le code discuté ici est disponible dans le référentiel Github.