Introduction

L'héritage est un concept fondamental de la programmation orientée objet, qui permet de créer une hiérarchie de classes pour modéliser des entités du monde réel. L'API Java Persistence (JPA) offre une solution puissante et flexible pour la persistance de ces entités dans une base de données relationnelle. Dans cet article, nous verrons comment JPA gère l'héritage et nous explorerons différentes stratégies de mappage des hiérarchies de classes vers les tables de la base de données.

Comprendre l'héritage en Java

Java prend en charge deux types d'héritage : l'héritage simple, dans lequel une classe ne peut étendre qu'une seule superclasse, et l'héritage multiple, obtenu par le biais d'interfaces. Dans le contexte de JPA, nous nous intéressons principalement à l'héritage simple, c'est-à-dire la capacité d'une classe à hériter des attributs et des méthodes d'une seule classe mère.

Considérons un scénario dans lequel vous avez une hiérarchie de classes représentant différents types d'employés : Employé, Gestionnaire et Ingénieur. Les classes Manager et Engineer étendent la classe Employee, formant ainsi une hiérarchie d'héritage.

public abstract class Employee {
    private Long id;
    private String name;
    private double salary;
}

@Entity
public class Manager extends Employee {
    private String department;
}

@Entity
public class Engineer extends Employee {
    private String project;
}

1. Stratégie de table unique

Dans la stratégie de la table unique, toutes les classes de la hiérarchie partagent une seule table de base de données, qui doit contenir toutes les colonnes nécessaires pour stocker les champs de la superclasse et de toutes ses classes enfants. Une colonne discriminante est utilisée pour distinguer les différents types d'objets.

import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee_type")
public abstract class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // ...
}

@Entity
@DiscriminatorValue("M")
public class Manager extends Employee {
    // ...
}

@Entity
@DiscriminatorValue("E")
public class Engineer extends Employee {
    // ...
}

L'annotation @DiscriminatorValue est utilisée pour spécifier la valeur de la colonne du discriminateur qui identifie le type d'objet. Cette valeur doit être unique pour toutes les classes héritées. Pour l'exemple ci-dessus, le schéma de la base de données contiendra la table employee, qui peut être créée comme suit :

create table employee (
    id int(11) AUTO_INCREMENT,
    employee_type varchar(1) NOT NULL,
    name varchar(255),
    salary double,
    department varchar(255),
    project varchar(255),
    primary key (id)
);

2. Stratégie d'adhésion

Dans la stratégie de jonction, chaque classe de la hiérarchie est associée à une table distincte. La mise en œuvre est très similaire à celle de la stratégie de la table unique, mais le schéma de la base de données est très différent.

import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "employee_type")
public abstract class Employee {
    // ...
}

@Entity
@DiscriminatorValue("M")
public class Manager extends Employee {
    // ...
}

@Entity
@DiscriminatorValue("E")
public class Engineer extends Employee {
    // ...
}

Dans cette stratégie, JPA s'attend à ce qu'il y ait trois tables dans le schéma de la base de données, qui peuvent être créées à l'aide des instructions suivantes :

create table employee (
    id int(11) AUTO_INCREMENT,
    employee_type varchar(1) NOT NULL,
    name varchar(255),
    salary double,
    primary key (id)
);

create table manager (
    id int(11) AUTO_INCREMENT,
    department varchar(255),
    primary key (id),
    foreign key (id) references employee(id)
);

create table engineer (
    id int(11) AUTO_INCREMENT,
    project varchar(255),
    primary key (id),
    foreign key (id) references employee(id)
);

3. Stratégie de la table par classe

Dans la stratégie Table par classe, chaque classe de la hiérarchie est associée à sa propre table, y compris ses attributs et ceux hérités de la superclasse.

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Employee {
    // ...
}

@Entity
public class Manager extends Employee {
    // ...
}

@Entity
public class Engineer extends Employee {
    // ...
}

Dans cette configuration, JPA s'attend à ce qu'il y ait deux tables dans le schéma de la base de données, qui peuvent être créées à l'aide des instructions suivantes :

create table manager (
    id int(11) AUTO_INCREMENT,
    name varchar(255),
    salary double,
    department varchar(255),
    primary key (id),
    foreign key (id) references employee(id)
);

create table engineer (
    id int(11) AUTO_INCREMENT,
    name varchar(255),
    salary double,
    project varchar(255),
    primary key (id),
    foreign key (id) references employee(id)
);

alert-info

La table employee n'est pas nécessaire, car la classe Employee est une classe abstraite et ne peut pas être instanciée.

Conclusion

Dans cet article, nous avons exploré la manière dont JPA gère l'héritage et examiné trois stratégies courantes de mappage des hiérarchies de classes vers les tables de la base de données. Le choix de la stratégie dépend des exigences spécifiques de votre application et des caractéristiques de votre modèle de données. Il est essentiel de comprendre ces stratégies et leurs implications pour concevoir des entités JPA efficaces et faciles à maintenir.