On souhaite enrichir notre service de deux manières :

  • Faire en sorte que notre méthode createMarin crée bien un Marin, plutôt que de retourner -1 systématiquement (ça sera plus utile !).

  • Ajouter deux méthodes : findMarinById(long) et getAllMarins(), qui retournent respectivement le marin dont on a donné la clé primaire, et la liste de tous les marins en base.

Nous avons déjà écrit du code de création d'entités JPA dans le chapitre précédent. Ce code est juste un appel à la méthode entityMananger.persist(), dans une transaction que nous avons gérée manuellement.

Dans un serveur d'applications, les choses ne se déroulent pas tout à fait de la même manière.

Tout d'abord, comme nous l'avons entrevu sur notre unité de persistance, les transactions ne sont plus gérées par notre code, mais par le serveur directement. Dans son comportement par défaut, lorsque nous entrons dans une méthode d'un EJB (on appelle ces méthodes des business methods , ou méthode métier), le serveur d'application a ouvert une transaction pour nous. Lorsque l'on quitte cette méthode, le serveur tente de valider cette transaction, sans que nous n'ayons rien à faire. Si cette validation échoue, alors une exception est générée.

De plus, l' entity manager que l'on utilise est fourni par le serveur d'applications, en tant que dépendance injectée. Ce mécanisme d'injection de dépendances nous permet de nous affranchir complètement de la création de nombre d'objets techniques. Voyons ces deux points sur l'exemple de notre EJB.


Cet exemple simple illustre ces deux concepts. Tout d'abord l'injection d'un entity manager : il suffit d'annoter une variable de type EntityManager avec @PersistenceContext. Cette annotation prend en attribut le nom de l'unité de persistance à laquelle cet entity manager est attaché. Ce nom doit donc être le même que celui que l'on a défini dans notre fichier persistence.xml.

À chaque fois que notre méthode createMarin(String) sera appelée, le serveur d'applications créera un nouvel entity manager , que nous pourrons utiliser directement.

On voit aussi que le code de gestion de la transaction a disparu : cette gestion est prise en charge par le serveur d'applications. En fait, appeler la méthode entityManager.getTransaction() jettera même une exception : lorsque nous sommes dans ce contexte, il n'est pas autorisé de tenter d'accéder à cette transaction.

Ce mécanisme d'injection de dépendances est apparu en JEE5, et il est massivement utilisé en JEE6. Il peut paraître un peu choquant au premier abord : nulle part on n'initialise cette variable em dans notre code, ce n'est qu'au moment de son utilisation qu'elle est initialisée par le serveur d'applications.

On peut donc maintenant enrichir le code de notre application cliente.


Notons que l'exécution de ce code client est indépendante de l'exécution de notre EJB. Cet EJB est en fonctionnement permanent, à la différence du code client, qui s'éteint une fois que la méthode main() a quitté. Or la base ne se réinitialise qu'au démarrage de notre unité de persistance, qui est maintenant attachée à l'application entreprise. Donc, si l'on lance notre client plusieurs fois de suite, on verra autant de marins "Surcouf" créés en base.

Notons enfin, que Netbeans a une bonne capacité à rafraîchir en temps réel l'application entreprise déployée, que le simple fait de modifier la classe Marin, ou notre EJB, peut entraîner immédiatement le redéploiement de cette application.

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