I. Généralités sur l'API Criteria
1. Présentation de Criteria
Criteria est un API qui permet de faire des requêtes sur des objets Entity rangés dans une base de données relationnelles comme on le fait avec JPQL; toutefois les requêtes Criteria sont de "type-safe", portables et faciles à modifier. Comme JPQL, l'API Criteria suit un schéma abstrait sur les instances des Entity concernées. L'API Metadata est associé à l'API Criteria pour permettre de modéliser la persistance des JPA Entity.
Comme L'API Criteria fonctionne sur le schéma abstrait des instances des Entity concernées, il permet de trouver, modifier ou supprimer des Entity persistantes en invoquant seulement des opérations Java sur des JPA Entity. C'est L'API Metamodel en fonctionnant de concert avec l'API Criteria qui permet de modéliser les objets des classes des JPA Entity pour les requêtes Criteria.
Avec l'API Criteria, contrairement à JPQL, les erreurs sont détectées plus tôt pendant la phase de compilation.Toutefois les requêtes JPQL et les requêtes de JPA Creteria sont identiques en termes de performance et d'efficacité. Pour les requêtes statiques simples c'est à dire les requêtes basées sur des chaînes de caractères, par exemple les requêtes nommées, mieux vaut utiliser JPQL; par contre, pour les requêtes dynamiques construites au moment de l'exécution, il faut privilégier plutôt l' emploi de l'API Criteria.
2. Structure de requête Criteria
L'API Criteria et l'API JPQL sont étroitement liés et permettent d'utiliser les mêmes type de requêtes. L'API criteria se trouve dans le package "javax.persistence.criteria".
Une requête simple de Criteria renvoie toutes les instances d'une classe JPA Entity présente dans la base de données.
2.1. L'interface CriteriaBuilder
Il existe deux interfaces principales utilisées pour créer des requêtes avec L' API Criteria: c'est l'interface CriteriaBuilder et l'interface CriteriaQuery. Dans un premier temps on doit obtenir un cadre pour un objet CriteriaBuilder pour pouvoir ensuite créer un objet CriteriaQuery; pour cela on utilise un objet EntityManager. On voit dans l'exemple ci-dessous les différentes étapes à suivre pour faire la requête proprement dite.
On définit CriteriaBuilder pour pouvoir créer des objets de type CriteriaQuery; les méthodes ci-dessous permettent de créer des objets de type CriteriaQuery:
- CreateQuery () – Cette méthode crée un objet de type CriteriaQuery - CriteriaQuery<Object> createQuery() - .
- CreateQuery (Classe) – Crée un CriteriaQuery utilisant des génériques pour éviter le casting du résultat de la classe.
- createTupleQuery () – Crée un CriteriaQuery qui retourne «un map» comme des Tuples d’objets , à la place de l’objet tableaux pour les requêtes multiselect.
- createCriteriaDelete (Classe) – Crée un CriteriaDelete qui permet de supprimer un lot d’objets directement sur la base de données ( voir JPA 2.1).
- createCriteriaUpdate (Classe) – Crée un CriteriaUpdate qui permet de mettre à jour un lot d’objets directement sur la base de données (JPA 2.1).
CriteriaBuilder définit également toutes les opérations de comparaison pris en charge et des fonctions utilisées pour définir les clauses de la requête.
Cette classe possède d'autres méthodes qui permettent de prendre en compte d'autres problématiques des requêtes sur des instances des JPA Entity de l'application à développer. ....
2.2. Exemples
La simple requête Criteria ci-dessous retourne toutes les instances de l'Entity P présentes dans la base de données:
EntityManagerFactory factory = Persistence.createEntityManagerFactory("Eclipselink_JPA");
EntityManager em = factory.createEntityManager(); CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Pet.class); Root pet = cq.from(Pet.class); cq.select(pet); TypedQuery q = em.createQuery(cq); List allPets = q.getResultList();
La requête JPQL équivalente est:
SELECT p FROM Pet p
Ci-dessous on a les différentes étapes suivies pour créer une requête Criteria:
- Utiliser une instance EntityManager pour créer un objet CriteriaBuilder.
- Crée un objet Query en créant une instance de l'interface Criteriaquery. Les attributs de l'objet Query seront modifiables par les détails de la requête.
- Définir un objet de type Root en faisant appel à la méthode "from" de de l'objet CriteriaQuery.
- Spécifiez le type de résultat de la requête en appelant la méthode select de l'objet CriteriaQuery.
- Préparer la requête pour l'exécution en créant une instance TypedQuery, en spécifiant le type de résultat de la requête.
- Exécutez la requête en appelant la méthode getResultList de l'objet TypedQuery. Comme cette requête retourne une collection d'entités, le résultat est stocké dans une liste.
En reprenant en détail le bout de programme qui illustre l'utilisation de l'API Criteria, on voit bien les six étapes qu'on a définies:
1) Pour créer une instance de CriteriaBuilder, on appelle la méthode getCriteriaBuilder d'une instance de EntityManager:
CriteriaBuilder cb = em.getCriteriaBuilder();
2) On utilise l'instance CriteriaBuilder pour créer un objet de type Query:
CriteriaQuery cq = cb.createQuery(Pet.class);
3) L'obet Query retournera des instances de l'Entity Pet. Pour créer un objet Query "typesafe", on spécifie le type de la requête lorsqu'on crée l'objet CriteriaQuery. On appelle ensuite la méthode from de l'objet Query pour définir la clause FROM de la requête; celle-ci retourne un objet Root:
Root pet = cq.from(Pet.class);
4) On appelle la méthode "select" de l'objet Query en lui passant comme paramètre l'objet de type Root; cela définit la clause de SELECT de la requête:
cq.select(pet);
5) Maintenant, on utilise l'objet Query pour créer un objet TypedQuery qui peut être exécuté sur la base de données. Les modifications apportées à l'objet Query sont saisies pour créer une requête prêt à exécuter:
TypedQuery q = em.createQuery(cq);
6) Exécutez cet objet Query en appelant sa méthode getResultList, car cette requête renverra plusieurs instances dde L'Entity. L'instruction suivante stocke les résultats dans un objet "List-collection-valued":
List allPets = q.getResultList();
...