Object
, qui est la super-classe de toutes les classes Java que l'on peut écrire. En général, lorsque l'on descend la hiérarchie, on commence par rencontrer des classes abstraites, puis des classes concrètes, de plus en plus spécialisées.
Le langage Java ne pose aucune contrainte sur ces hiérarchies : une classe abstraite peut parfaitement étendre une classe concrète.
Nous avons vu que pour déclarer une entité JPA, il fallait poser l'annotation
@Entity
sur la classe. Nous avons en tout trois possibilités pour chaque classe d'une hiérarchie :
@Entity
: dans ce cas la classe est une entité JPA, et ses champs seront enregistrés en base suivant les règles que nous allons voir.
@MappedSuperClass
: dans ce cas la classe n'est pas une entité JPA, mais ses champs seront enregistrés en base, suivant les règles que nous allons voir.
@Entity
peut étendre ou être étendue par une classe
@MappedSuperClass
, ou non annotée.
Les règles d'enregistrement des champs en base sont très simples :
@Entity
est dite "persistante" : ses champs sont enregistrés en base dans une table associée à la classe, définie par la stratégie d'enregistrement de l'héritage. Cette classe est une entité, on peut faire des requêtes dessus.
@MappedSuperClass
est aussi une classe "persistante", mais ce ne n'est pas une entité, et à ce titre, on ne peut donc pas faire de requêtes dessus. Ses champs sont enregistrés en base, et sont associés aux champs de toutes les entités des sous-classes de cette classe.
Exemple 27. Hiérarchie simple
// // Classe Personne // public class Personne { private String nom ; private String prenom ; // reste de la classe } // // Classe Marin // public class Marin extends Personne { private Bateau bateau ; // reste de la classe }
nom
,
prenom
et
bateau
: dans quelle table doit-on créer les colonnes associées ?
Personne
peut aussi enregistrer des marins. Peut-on enregistrer cette information en base ?
Personne
a besoin de deux colonnes :
nom
et
prenom
, que nous pouvons d'emblée enregistrer dans une table
Personne
.
Comment enregistre-t-on le complément d'information amené par la sous-classe
Marin
? Trois solutions s'offrent à nous :
Personne
. Dans ce cas les instances de
Marin
seront enregistrées dans la même table que
Personne
, et nous aurons besoin d'une colonne technique pour différencier ces entités.
Marin
. Cette table devra alors récupérer les colonnes associées aux champs de
Personne
. Notre table
Marin
comportera trois colonnes :
nom
,
prenom
et une colonne de jointure
bateau_id
.
Marin
en jointure de la table
Personne
. La table
Personne
n'est pas touchée, et la table
Marin
ne comporte qu'une colonne de jointure
bateau_id
.
SINGLE_TABLE
: chaque hiérarchie d'entités JPA est enregistrée dans une table unique. Cette stratégie est efficace pour les modèles de faible profondeur d'héritage. Si le nombre d'entités dans une hiérarchie est trop important, les limites de la base de données sous-jacente peuvent le rendre impossible à utiliser.
JOINED
: chaque entité JPA est enregistrée dans sa propre table. Les entités d'une hiérarchie sont en jointure les unes des autres. Ce modèle est inutilisable dans le cas de hiérarchies trop importantes, pour des raisons de performance. C'est pourtant le seul qui permet de vérifier la première forme normale.
TABLE_PER_CLASS
: seules les entités associées à des classes concrètes sont enregistrées dans leur propre table. Ce modèle est un compromis honnête entre les deux approches précédentes, notamment dans le cas des hiérarchies importantes. Si l'on réfléchit bien à la distribution des classes concrètes du modèle, et des super-classes non enregistrées, il peut même se révéler très efficace.