5. Clause From

5.1. Définition des entités

Dans un premier temps, la clause From doit donner la liste des entités sur lesquelles la requête doit être exécutée. Dans tous les cas, on doit donner au moins une entité. Une entité peut être désignée par le nom complet de sa classe, ou son nom, qui joue le rôle d'alias. Ce nom est la valeur de l'attribut name de l'annotation @Entity. Rappelons enfin deux choses :
  • une classe annotée @MappedSuperClass n'est pas une entité, on ne peut donc pas faire de requête dessus ;
  • il est parfaitement possible de faire une requête sur une classe abstraite.

5.2. Jointures dans la clause From

Prenons un modèle composé de trois classes : Personne, étendue par Marin et Capitaine. Ces trois classes sont concrètes, et sont des entités. Une quatrième classe, Bateau, porte une relation passager, de type Personne, annotée @OneToOne, et une deuxième, equipage, également de type Passager, annotée @OneToMany On remarquera que cet exemple porte une relation polymorphique ( passager peut recevoir des instances de nos trois classes Passager, Marin et Capitaine. On choisira une strategie JOINED pour la mise en base.

5.2.1. Jointures naturelles

On peut exprimer une jointure de plusieurs façons dans une requête JPQL, tout comme en SQL. La première façon peut être implicite ou explicite. Supposons que l'on cherche le passager d'un bateau dont le nom est passé en paramètre.

Exemple 43. Une première jointure JPQL implicite

select bateau.passager 
from Bateau bateau 
where bateau.nom = :nom

Cette requête JPQL se traduit en EclipseLink par une commande SQL qui comporte une jointure ( left outer join) entre la table Bateau et la table Personne. Si l'on n'avait pas ajouter la clause where, on aurait obtenu en résultat la liste de toutes les personnes qui sont passagers d'un bateau. On aurait pu écrire une jointure explicite de la façon suivante :

Exemple 44. Une première jointure JPQL explicite

select personne 
from Bateau bateau 
	join bateau.passager personne 
where bateau.nom = :nom

Ces deux écritures sont équivalentes du point de vue JPQL, et génèrent le même code SQL dans EclipseLink.

5.2.2. Jointures externes

Comme en SQL, les jointures externes permettent de préserver l'existence des entités du côté gauche de la jointure, quand bien même ces entités n'auraient pas d'entité jointe. Une jointure externe s'exprime de la façon suivante. Comme exemple, écrivons une requête qui permet d'afficher la liste des bateaux et de leurs passagers.

Exemple 45. Une jointure externe JPQL

select bateau 
from Bateau bateau 
	left join bateau.passager personne 
where bateau.nom like :nom

Le SQL généré par EclipseLink est le suivant :

Exemple 46. SQL généré par une jointure externe JPQL

SELECT t1.ID, t1.NOM, t1.PASSAGER_ID 
FROM BATEAU t1 
     LEFT OUTER JOIN PERSONNE t0 ON (t0.ID = t1.PASSAGER_ID) 
WHERE (t1.NOM LIKE ?)

On constate que l'on a bien une jointure externe générée, qui nous permettra d'obtenir toute la liste des bateaux, quand bien même ils n'ont pas de passagers. Si l'on retire le mot-clé left de notre requête JPQL, on obtient le code généré suivant :

Exemple 47. SQL généré sans jointure externe JPQL

SELECT t1.ID, t1.NOM, t1.PASSAGER_ID 
FROM PERSONNE t0, BATEAU t1 
WHERE ((t1.NOM LIKE ?) AND (t0.ID = t1.PASSAGER_ID))

Dans ce cas EclipseLink nous génère une jointure interne, et ne sortiront dans notre requête que les bateaux qui ont un passager.

5.2.3. Jointures de type fetch

Ces jointures sont propres au JPQL, cette notion n'existe pas en SQL. Elles permettent de charger explicitement la relation d'une entité, même si les objets de cette relation ne font pas partie du résultat de la sélection. Cela permettra de faire l'économie de la lecture de ces objets en relation lors de l'exploitation du résultat. Si l'on reprend notre exemple JPQL précédent, on constate que seule la clé primaire de notre passager est présente dans la requête. Lors de l'exploitation de cette requête, si l'on en vient à lire ce passager, une demande devra partir sur le cache de l' entity manager . Si le cache ne possède pas l'objet, alors il faudra aller le lire en base, ce qui impliquera un aller et retour supplémentaire avec la base. La jointure fetch permet de lire les objets en relation directement, et donc de faire l'économie de cet aller et retour. Modifions notre requête afin de mettre en œuvre cette technique.

Exemple 48. Jointure fetch

select bateau 
from Bateau bateau left join fetch bateau.passager 
where bateau.nom like :nom

Remarquons tout d'abord deux choses :
  • le mot-clé fetch se place à droite du mot-clé join ;
  • on ne peut plus poser d'alias sur le champ à droite du join.
Enfin, notons que ces jointures ne sont pas autorisées dans des requêtes imbriquées. Voici le SQL généré par EclipseLink pour cette requête :

Exemple 49. SQL généré pour une jointure fetch

SELECT t1.ID, t1.NOM, t1.PASSAGER_ID, 
       t0.ID, t0.DTYPE, t0.PRENOM, t0.NOM 
FROM BATEAU t1 LEFT OUTER JOIN PERSONNE t0 ON (t0.ID = t1.PASSAGER_ID) 
WHERE (t1.NOM LIKE ?)
On constate que les champs de Personne ( nom et prenom) ont été ajoutés à la requête, ce qui va autoriser la construction de la relation passager de chaque instance de Bateau dès l'exécution de cette requête.

5.3. Remarque finale sur les jointures en JPQL

On prendra garde que le fait d'écrire une jointure dans une requête JPQL contraint le résultat a posséder un résultat pour cette jointure, quand bien même on n'utilise pas l'entité en relation dans la clause where, même dans le cas où cette clause where n'existe pas. Considérons par exemple la requête JPQL suivante.

Exemple 50. Requête jointe sans clause where

select bateau 
from Bateau bateau 
     join bateau.passager personne 

Bien que cette requête ne pose aucune condition sur la relation passager, la jointure sera établie dans le SQL généré. En particulier, si aucune instance de Personne ne se trouve en base, aucun bateau ne sera sélectionné par cette requête.
JPA & EJB
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction
1. Objet du mapping objet / relationnel
2. Un peu d'histoire
Un premier exemple
1. Introduction
2. Création de l'environnement technique
2.1. Introduction
2.2. Création de la base Derby
2.3. Création du projet NetBeans et d'une première entité
2.4. Structure d'un projet persistant
2.5. Une première classe persistante
2.6. Un premier fichier persistence.xml
3. Utilisation de ce premier exemple
3.1. Écriture du code d'utilisation
3.2. Exécution de notre premier exemple
3.3. Modification de la class Marin
3.4. Opérations CRUD
Mettre un jeu de classes en base
1. Introduction
2. Définition d'une entité JPA
2.1. Écriture de l'entité
2.2. Annotation de l'entité
2.3. Annotations des champs
2.4. Exemple d'utilisation
3. Opérations sur les entités
3.1. Introduction
3.2. Opération PERSIST
3.3. Opération REMOVE
3.4. Opération REFRESH
3.5. Opération DETACH
3.6. Opération MERGE
4. Mise en relation d'entités
4.1. Introduction
4.2. Relations unidirectionnelles et bidirectionnelles
4.3. Relation 1:1
4.4. Relation 1:p
4.5. Relation p:1
4.6. Relation n:p
4.7. Comportement cascade
4.8. Effacement des entités orphelines
5. Charger des entités et leurs relations
6. Objets inclus
6.1. Introduction
6.2. Déclaration d'un objet inclus
6.3. Utilisation d'objets inclus
6.4. Cas où l'objet inclus est nul
6.5. Renommer les colonnes incluses
6.6. Collections d'objets inclus
L'API Collection en base
1. Introduction
2. Enregistrer une collection d'entités
2.1. Enregistrement d'une collection simple
2.2. Enregistrement d'un Set
2.3. Enregistrement d'une List
3. Enregistrer une collection de types de base
4. Enregistrement d'une Map
4.1. Table de hachage de type (type de base, entité)
4.2. Cas où la clé est un champ de la valeur
4.3. Cas d'une table (entité, entité)
Héritage
1. Introduction
2. Enregistrement d'une hiérarchie de classes
2.1. Entité et super-classe non enregistrée
2.2. Position du problème
2.3. Trois façons de faire
3. Stratégie SINGLE_TABLE
3.1. Fonctionnement
3.2. Mise en place
3.3. Limitations
4. Stratégie JOINED
4.1. Fonctionnement
4.2. Mise en place
4.3. Limitations
5. Stratégie TABLE_PER_CLASS
5.1. Fonctionnement
5.2. Mise en place
5.3. Limitations
Requêtes
1. Introduction
2. Un premier exemple
2.1. Écriture d'une première requête
2.2. Exécution d'une première requête
2.3. Exécution d'une première requête d'agrégation
3. Définition de requêtes
3.1. Requêtes dynamiques
3.2. Requêtes paramétrées
3.3. Requêtes nommées
3.4. Requêtes natives
4. Exécution, analyse du résultat
4.1. Exécution d'une requête dynamique
4.2. Exécution d'une requête nommée
4.3. Analyse du résultat
4.4. Cas des résultats de grande taille
4.5. Remarques
5. Clause From
5.1. Définition des entités
5.2. Jointures dans la clause From
5.3. Remarque finale sur les jointures en JPQL
6. Clause Where
6.1. Variables et chemins dans une clause where
6.2. Expressions conditionnelles et opérateurs
6.3. Requêtes imbriquées
6.4. Opérateurs any, all et some
6.5. Expressions fonctionnelles
7. Clauses Group By et Having
8. Opérations Update et Delete
EJB
1. Introduction
2. Un premier exemple
2.1. Introduction
2.2. Installation dans Glassfish à l'aide de Netbeans
2.3. Création d'un premier EJB
2.4. Déploiement de notre premier EJB
2.5. Création d'un client
3. Mise en oeuvre du pattern session facade
3.1. Introduction
3.2. Modèle objet
3.3. Définition de l'unité de persistance
3.4. Assemblage de notre application
3.5. Assemblage et déploiement
3.6. Utilisation du client
4. Opération de persistance en façade
4.1. Introduction
4.2. Enrichissement du service
4.3. Création de la méthode findMarinById(long)
4.4. Ajout de la méthode findAllMarins()
4.5. Utilisation dans un code client
5. Types d'EJB
5.1. Introduction
5.2. Qu'est-ce qu'un EJB ?
5.3. Écriture d'un EJB session
5.4. Qu'est-ce qu'une méthode métier ?
5.5. EJB avec ou sans état
5.6. Gestion des transactions
5.7. Restrictions
6. Cycle de vie d'un EJB
6.1. Cas des EJB sans état
6.2. Cas des EJB avec état
6.3. Injection de dépendances
7. Transaction gérée par l'EJB
7.1. Introduction
7.2. Déclaration du mode transactionnel
7.3. Gestion de la transaction
7.4. Fonctionnement de la transaction
7.5. Cas des EJB avec état
8. Transaction gérée par le serveur
8.1. Introduction
8.2. Déclaration du mode transactionnel
8.3. Gestion de la transaction
8.4. Fonctionnement de la transaction
8.5. Remarques
9. Intercepteurs
9.1. Introduction
9.2. Aperçu général
9.3. Cycle de vie d'un intercepteur
9.4. Object InvocationContext
9.5. Interception d'un EJB ou d'une méthode métier
9.6. Exemple de mise en œuvre d'un intercepteur