La sémantique de la List est différente de celle du Set. On peut ajouter plusieurs fois le même élément dans une liste, sans que cela ne pose de problème. La contrainte est que, lorsque l'on relit les éléments d'une liste, alors on doit obtenir ces éléments dans le même ordre que celui dans lequel on les a enregistrés. En d'autres termes, une liste conserve l'ordre dans lequel les éléments ont été ajoutés.

Ce point est réellement problématique en JPA, et d'ailleurs n'est pas supporté en JPA 1.0.

Lorsque l'on pose une annotation @OneToMany sur une relation de type liste, sans autre précision, alors l'ordre des éléments de cette liste sera perdu après une relecture en base.

On peut spécifier un ordonnancement des éléments de deux façons.

  • On peut choisir un champ particulier de ces éléments, et indiquer à JPA que lorsque l'on parcourt cette liste, alors ses éléments doivent être triés par ordre croissant ou décroissant de cet élément. Cette fonctionnalité est disponible en JPA 1.0.

  • On peut demander à JPA de créer une colonne technique, dans laquelle il va entretenir un index, qui permettra de conserver la sémantique Java sur cette liste. Cette fonctionnalité n'est pas disponible en JPA 1.0, elle n'existe qu'à partir de JPA 2.0.

Voyons ceci sur un exemple.


Notre entité Bateau porte une relation marins, multivaluée, de type 1:p. Cela signifie qu'un bateau peut posséder plusieurs marins par cette relation, et qu'un marin donné ne peut appartenir qu'à un unique bateau.

Notre champ Java est déclaré comme étant de type List, mais la sémantique attachée à ce type n'est pas respectée par JPA. Les marins que l'on enregistre dans cette liste ont donc toutes les chances d'être relus dans un ordre aléatoire.

Pour pallier ce défaut, JPA 1.0 introduit l'attribut OrderBy, que nous utilisons ici. Cet attribut doit désigner un champ de l'entité cible de cette relation, ici Marin. À chaque lecture de la relation marins, JPA ordonnera nos marins en fonction de leur nom, garantissant ainsi un ordre fixe du contenu de la liste. Cet ordre n'est toutefois pas nécessairement le même que celui dans lequel nos marins ont été enregistrés. La sémantique Java n'est donc toujours pas exactement respectée.

L'utilisation de cet attribut n'a pas d'impact sur la structure de base générée. Seules les requêtes SQL sont modifiées s'il est présent.

Si l'on persiste une telle liste, elle ne se triera pas magiquement dans la mémoire de notre application ! D'une façon générale, cette annotation n'impose pas l'ordre des éléments dans la liste marins de nos objets bateau. Elle ne fait qu'imposer l'ordre de ces éléments lors de la lecture en base.

L'argument de @OrderBy peut être une liste de champs de l'entité cible, séparés par des virgules. On peut ajouter le mot-clé ASC ou DESC après chacun de ces champs, afin de préciser si le classement doit se faire dans l'ordre croissant ou décroissant.

De plus, on prendra garde au fait que cet ordre ne s'applique qu'au moment où l'on lit cette liste de la base. En particulier, si l'on remplit cette liste avec des valeurs rangées dans un ordre qui ne respecte pas l'annotation, JPA ne fait rien pour réordonnancer la liste. Lors de l'itération suivante, même si elle a été mise en base, l'ordre dans lequel les objets seront lus par itération sera celui dans lequel on les a mis.

JPA 2.0 propose un respect strict de la sémantique de la List Java. Voyons ceci sur un exemple.


Cet exemple est le même que le précédent, sauf que nous avons utilisé l'annotation @OrderColumn au lieu de l'attribut orderBy. Cette annotation ajoute une colonne technique, nommée marins_order, utilisée pour enregistrer l'ordre dans lequel nos marins ont été enregistrés.

Dans le cas de la présence d'une table de jointure (cas @OneToMany unidirectionnel, ou @ManyToMany), cette colonne technique est présente dans la table de jointure, comme on le voit sur la structure que JPA génère pour notre exemple.


Dans le cas où nous n'avons pas de table de jointure (relation @OneToMany bidirectionnelle), alors la colonne technique est créée dans la table qui porte la colonne de jointure, c'est-à-dire la table de l'entité maître de la relation.


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