3. Stratégie SINGLE_TABLE

3.1. Fonctionnement

Cette approche consiste à enregistrer toute une hiérarchie de classes dans une table unique associée à la première classe (en partant de la classe Object) annotée par @Entity. Cette table doit donc comporter des colonnes pour tous les champs de toutes les classes de la hiérarchie, du moins celles annotées par @Entity ou @MappedSuperClass. On prendra donc garde aux éventuels problèmes de collisions de nom au niveau des colonnes. Cette table enregistrera toutes les instances de ces classes : en général plusieurs instances peuvent donc cohabiter. Il n'y a pas d'autre moyen pour discriminer ces instances que de créer une colonne technique, afin d'enregistrer de quelle instance il s'agit, pour chaque ligne. Il est possible qu'une ligne donnée de cette table n'utilise pas toutes les colonnes définies. Dans notre exemple, toutes les instances de Personne auront une valeur nulle dans la colonne de jointure Bateau.

3.2. Mise en place

Prenons l'exemple du modèle suivant : une classe Personne est étendue par une classe Maire. La classe Maire définit une relation vers une Commune.

Exemple 28. Stratégie SINGLE_TABLE

//
 // Entité Personne
 //
 @Entity
 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
 @DiscriminatorColumn(name="TYPE_ENTITE")
 @DiscriminatorValue("PERSONNE")
 public  class Personne  implements Serializable {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     @Column(length=40)
     private String nom ;

     @Column(length=40)
     private String prenom ;
    
     // reste de la classe
}

 //
 // Entité Maire
 //
 @Entity
 @DiscriminatorValue("MAIRE")
 public  class Maire  extends Personne {

     @OneToOne
     private Commune commune ;
    
     // reste de la classe
}

 //
 // Entité Commune
 // 
 @Entity
 public  class Commune  implements Serializable {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     private String name ;
    
     // reste de la classe
}

On choisit une stratégie SINGLE_TABLE. Cette stratégie est indiquée par l'annotation @Inheritance. Cette annotation ne peut être posée qu'une seule fois par hiérarchie de classe, sur la classe qui sert de racine à cette hiérarchie. On redéfinit ici le nom de la colonne technique qui va nous permettre de discriminer les instances de Personne et les instances de Maire dans cette table, par l'annotation @DiscriminatorColumn. De même, cette annotation ne doit être posée qu'une seule fois sur toute la hiérarchie. Enfin pour nos deux entités Personne et Maire, on définit la valeur utilisée pour discriminer les instances, par l'annotation @DiscriminatorValue. Examinons le schéma obtenu.
Schéma pour une hiérarchie SINGLE_TABLE

Figure 23. Schéma pour une hiérarchie SINGLE_TABLE


On remarque la présence de la colonne TYPE_ENTITE dans la table Personne, de même que la colonne de jointure commune_id, définie par l'entité Maire.

3.3. Limitations

Cette approche présente deux limitations : sur le nombre de colonnes d'une part, et sur la sémantique de chaque colonne. Cette approche fonctionne bien si la hiérarchie de classe à enregistrer n'est pas trop profonde, et si l'on n'a pas trop de champs dans cette hiérarchie. Dans le cas contraire, outre les collisions de noms à gérer, deux problèmes peuvent survenir, qui peuvent rendre cette stratégie impossible à utiliser. Effectivement, cette approche peut mener à un très grand nombre de champs dans la table d'enregistrement. Or, les serveurs de base de données imposent une limite au nombre de colonnes qu'une table peut comporter. De plus, une deuxième limite existe, plus subtile : chaque ligne doit tenir dans un espace mémoire limité. Cet espace mémoire peut être rapidement dépassé si l'on a trop de colonnes de grande taille, comme des VARCHAR de tailles importantes. Par ailleurs, il faut garder présent à l'esprit que chaque ligne de cette table aura en général un certain nombre de colonnes nulles. Il faut donc être très prudent lorsque l'on ajoute des contrainte du type not null ou optional=false sur certaines colonnes. Dans notre exemple, il n'est pas possible d'ajouter une contrainte pour rendre obligatoire la relation Maire - Commune. Cette contrainte se traduirait par une commande SQL not null sur la colonne commune_id, or cette colonne va porter des valeurs nulles pour toutes les instances de Personne qui ne sont pas des Maire.
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