Requêtes de critères JPA

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 fonctionnalités principales d'Hibernate. L'API de critères nous permet de créer un objet de requête de critères par programme, dans lequel nous pouvons appliquer différents types de règles de filtrage et de conditions logiques.

Since Hibernate 5.2, the Hibernate Criteria API is deprecated and new development is focused on the JPA Criteria API. Nous allons explorer comment utiliser Hibernate et JPA pour créer des requêtes de critères.

2. Dépendances 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 fichierpom.xml:


    org.hibernate
    hibernate-core
    5.3.2.Final

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

3. Exemple simple utilisant des critères

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

Nous avons une classeItem 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
}

Examinons 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 démonstration simple de la façon d’obtenir tous les éléments. Voyons ce qui a été fait, étape par étape:

  1. Créer une instance deSession à partir de l'objetSessionFactory

  2. Créez une instance de CriteriaBuilder en appelant la méthodegetCriteriaBuilder()

  3. Créez une instance deCriteriaQuery en appelant lesCriteriaBuildercreateQuery() method

  4. Créez une instance deQuery en appelant la méthodeSessioncreateQuery()

  5. Appelez la méthodegetResultList() de l'objetquery qui nous donne les résultats

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

3.1. Utilisation deExpressions

The CriteriaBuilder can be used to restrict query results based on specific conditions. En utilisant la méthodeCriteriaQuery where() et en fournissant lesExpressions créés parCriteriaBuilder.

Voici quelques exemples deExpressions couramment utilisés:

Pour obtenir des articles dont le prix est supérieur à 1000:

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

Ensuite, obtenir les éléments ayantitemPrice inférieurs à 1000:

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

Les éléments ayantitemNames contiennentChair:

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

Enregistrements ayant desitemPrice 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 null:

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

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

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

Vous pouvez également utiliser les méthodesisEmpty() etisNotEmpty() pour tester si unList dans une classe est vide ou non.

Maintenant, inévitablement, la question se pose de savoir si nous pouvons combiner deux ou plus des comparaisons ci-dessus ou non. La réponse est, bien sûr, oui -the Criteria API allows us to easily chain 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 avecLogical OR:

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

Pour obtenir des éléments correspondant aux conditions définies ci-dessus jointes avecLogical AND:

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

3.2. Tri

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

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

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

Dans la section suivante, nous verrons comment utiliser les 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:

Obtenir 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:

FonctionAggregate pourAverage:

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 sontsum(),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'APICriteria.

CriteriaUpdate a une méthodeset() qui peut être utilisée pour fournir de nouvelles valeurs pour les enregistrements de la base de données:

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();

Dans l'extrait de code ci-dessus, nous créons une instance deCriteriaUpdate<Item>  à partir duCriteriaBuilder et utilisons sa méthodeset() pour fournir de nouvelles valeurs pour lesitemPrice. Pour mettre à jour plusieurs propriétés, il suffit de appelez la méthodeset() plusieurs fois.

3.5. CriteriaDelete

CriteriaDelete, comme son nom l'indique, permet une opération de suppression à l'aide de l'APICriteria. Tout ce dont nous avons besoin est de créer une instance deCriteriaDelete et d'utiliser la méthodewhere() pour appliquer des 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. Avantage sur HQL

Dans les sections précédentes, nous avons expliqué comment utiliser les requêtes de critères.

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

Nous pouvons simplement écrire des requêtes plus flexibles et dynamiques par rapport à HQL simple. La logique peut être refactorisée avec l'EDI et offre tous les avantages en termes de sécurité de type du langage Java lui-même.

Il y a bien sûr aussi quelques inconvénients, notamment autour des jointures plus complexes.

Donc, d'une manière générale, nous devrons utiliser le meilleur outil pour le travail - qui peut être l'API Criteria dans la plupart des cas, mais il y a certainement des cas où nous devrons aller plus bas.

5. Conclusion

Dans cet article, nous nous sommes concentrés sur les bases des requêtes de critères dans Hibernate et JPA, ainsi que sur certaines des fonctionnalités avancées de l'API.

Le code discuté ici est disponible dans lesGithub repository.