Relation un à un dans JPA

Relation un à un dans JPA

1. introduction

Dans ce didacticiel, nous allons examiner différentes manières de créer des mappages un-à-un dans JPA.

Nous aurons besoin d'une compréhension de base du framework Hibernate, veuillez donc consulter nosGuide to Hibernate 5 with Spring pour plus d'informations.

Lectures complémentaires:

Présentation des types JPA / Hibernate Cascade

Un aperçu rapide et pratique des types de cascade JPA / Hibernate.

Read more

Tutoriel Annotation Hibernate Un à Plusieurs

Dans ce didacticiel, nous allons examiner le mappage un-à-plusieurs à l'aide d'annotations JPA avec un exemple pratique.

Read more

2. La description

Supposons que nous construisions un système de gestion des utilisateurs et que notre patron nous demande de stocker une adresse postale pour chaque utilisateur. Un utilisateur aura une adresse postale et une adresse postale ne sera associée qu’à un seul utilisateur.

Voici un exemple de relation biunivoque, dans ce cas entreuser andaddress entities.

Voyons comment nous pouvons mettre cela en œuvre dans les sections suivantes.

3. Utiliser une clé étrangère

3.1. Modélisation avec une clé étrangère

Examinons lesER diagram suivants, qui représentent un mappage un-à-un basé sur une clé étrangère:

An ER Diagram mapping Users to Addresses via an address_id foreign key

Dans cet exemple, la scolumnaddress_id dansusers est laforeign key àaddress.

3.2. Mise en œuvre avec une clé étrangère dans JPA

Commençons par créer la classeUser  et annotons-la de manière appropriée:

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;
    //...

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "address_id", referencedColumnName = "id")
    private Address address;

    // ... getters and setters
}

Notez quewe place the @OneToOne annotation sur le champ d'entité associé,Address.

De plus,we need to place the @JoinColumn annotation pour configurer le nom de la colonne dans la tableusers qui correspond à la clé primaire dans la tableaddress. Si nous ne fournissons pas de nom, Hibernate ferafollow some rules pour en sélectionner un par défaut.

Enfin, notez dans l'entité suivante que nous n'utiliserons pas l'annotation@JoinColumn ici. C'est parce que nous n'en avons besoin que du côtéowning de la relation de clé étrangère. Simply put, whoever owns the foreign key column gets the @JoinColumn annotation.

La sentitéAddress 'avère un peu plus simple:

@Entity
@Table(name = "address")
public class Address {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;
    //...

    @OneToOne(mappedBy = "address")
    private User user;

    //... getters and setters
}

Nous devons également placer ici la sannotation@OneToOne . C’est parce qu’il s’agit d’unbidirectional relationship. The address side of the relationship is called the non-owning side. 

4. Utilisation d'une clé primaire partagée

4.1. Modélisation avec une clé primaire partagée

Dans cette stratégie, au lieu de créer une nouvelle colonneaddress_id, we’ll mark the primary key column (user_id) of the address table as the foreign key to the users table:

An ER diagram with Users Tied to Addresses where they share the same primary key values

Nous avons optimisé l'espace de stockage en utilisant le fait que ces entités ont une relation un à un entre elles.

4.2. Mise en œuvre avec une clé primaire partagée dans JPA

Notez que nos définitions ne changent que légèrement:

@Entity
@Table(name = "users")
public class User {

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

    //...

    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
    private Address address;

    //... getters and setters
}
@Entity
@Table(name = "address")
public class Address {

    @Id
    @Column(name = "id")
    private Long id;

    //...

    @OneToOne
    @MapsId
    private User user;

    //... getters and setters
}

@MapsId tells Hibernate to use the id column of address as both primary key and foreign key. Notez également quethe @Id column of the Address entity no longer uses the @GeneratedValue annotation.

L'attributmappedBy est maintenant déplacé vers la classeUser car la clé étrangère est maintenant présente dans le stableaddress .

5. Utiliser une table de jointure

Les mappages un-à-un peuvent être de deux types -Optional etMandatory. So far, we’ve seen only mandatory relationships.

Maintenant, imaginons que nos employés soient associés à un poste de travail. C'est un à un, mais parfois un employé peut ne pas avoir de poste de travail et vice-versa.

5.1. Modélisation avec une table de jointure

Les stratégies dont nous avons discuté until now force us to put null values in the column to handle optional relationships.

Typiquement, nous pensons àmany-to-many relationships lorsque nous considérons une table de jointure,but, using a join table, in this case, can help us to eliminate these null values:

An ER diagram relating Employees to Workstations via a Join Table

Maintenant, chaque fois que nous avons une relation, nous allons faire une entrée dans leemp_workstation table et éviter les nulls altogether.

5.2. Mise en œuvre avec une table de jointure dans JPA

Notre premier exemple utilise@JoinColumn. Cette fois, nous utiliserons@JoinTable:

@Entity
@Table(name = "employee")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    //...

    @OneToOne(cascade = CascadeType.ALL)
    @JoinTable(name = "emp_workstation",
      joinColumns =
        { @JoinColumn(name = "employee_id", referencedColumnName = "id") },
      inverseJoinColumns =
        { @JoinColumn(name = "workstation_id", referencedColumnName = "id") })
    private WorkStation workStation;

    //... getters and setters
}
@Entity
@Table(name = "workstation")
public class WorkStation {

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

    //...

    @OneToOne(mappedBy = "workStation")
    private Employee employee;

    //... getters and setters
}

@JoinTable indique à Hibernate d'utiliser la stratégie de table de jointure tout en maintenant la relation.

De plus,Employee  est le propriétaire de cette relation car nous avons choisi d'y utiliser l'annotation de table de jointure.

6. Conclusion

Dans ce didacticiel, nous avons appris différentes manières de maintenir une association un-à-un dans JPA et Hibernate et à utiliser chacune d'elles.

Le code source de ce tutoriel peut être trouvéover on GitHub.