Mapping avec JPA


De UML à SQL : Relation OneToOne

Article faisant partie d’une série présentant les différentes annotations permettant de traduire des relations entre classes persistantes en bases de données relationnelles.

 Relation OneToOne unidirectionnelle

Nous allons voir maintenant une relation OneToOne unidirectionnelle entre une classe B et une classe C. Le lien se fera de B vers C.

Diagramme de classe

Code Java

Code de la classe B :

  1. @Table( name = "T_TABLE_B" )
  2. public class ClasseB implements Serializable
  3. {
  4.   @Id
  5.   @GeneratedValue( strategy = GenerationType.IDENTITY )
  6.   @Column( name = "B_ID" )
  7.   private Long id;
  8.  
  9.   @Column( name = "B_REMARQUE" )
  10.   private String remarque;
  11.  
  12.   @OneToOne
  13.   @JoinColumn( name = "C_ID_FK" )
  14.   private ClasseC attributC;
  15.  ...

Télécharger

Nous avons un attribut de type ClasseC nous permettant d’accéder à un objet C depuis un objet B.

Le code la classe C :

  1. @Table( name = "T_TABLE_C" )
  2. public class ClasseC implements Serializable
  3. {
  4.   @Id
  5.   @GeneratedValue( strategy = GenerationType.IDENTITY )
  6.   @Column( name = "C_ID" )
  7.   private Long id;
  8.  
  9.   @Column( name = "C_REMARQUE" )
  10.   private String remarque;
  11. ...

Télécharger

Comme la relation est unidirectionnelle, nous n’avons pas d’attribut de type ClasseB dans C.

Les tables correspondantes

La table correspondant à la classe B :

La table correspondant à la classe C :

Et voici le script SQL   permettant de générer les tables :

Script de la table B :

  1. CREATE TABLE `T_TABLE_B` (
  2.   `B_ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
  3.   `B_REMARQUE` VARCHAR(255) DEFAULT NULL,
  4.   `C_ID_FK` BIGINT(20) DEFAULT NULL,
  5.   PRIMARY KEY (`B_ID`),
  6.   KEY `FK_T_TABLE_B_C_ID_FK` (`C_ID_FK`),
  7.   CONSTRAINT `FK_T_TABLE_B_C_ID_FK` FOREIGN KEY (`C_ID_FK`) REFERENCES `T_TABLE_C` (`C_ID`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=latin1

Télécharger

Script de la table C :

  1. CREATE TABLE `T_TABLE_C` (
  2.   `C_ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
  3.   `C_REMARQUE` VARCHAR(255) DEFAULT NULL,
  4.   PRIMARY KEY (`C_ID`)
  5. ) ENGINE=InnoDB DEFAULT CHARSET=latin1

Télécharger

Cas d’une relation 1 —> 1

Dans le diagramme de classes précédent, nous avions une cardinalité de 1 —> 0,1 entre B et C, ce qui veut dire que l’on n’est pas obligé d’avoir un objet C pour chaque objet B créé. D’autre part, nous avons bien le champ C_ID_FK qui est défini avec la valeur NULL autorisée. Maintenant si nous désirons que pour tout B nous ayons un C correspondant, nous devrons interdire NULL sur la clé étrangère.

Pour cela, il suffit de modifier la classe B en précisant l’annotation suivante :

  1. @OneToOne
  2.   @JoinColumn( name = "C_ID_FK",nullable = false )
  3.   private ClasseC attributC;

Télécharger

ce qui donne maintenant la table :

Et le script SQL   correspondant :

  1. CREATE TABLE `T_TABLE_B` (
  2.   `B_ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
  3.   `B_REMARQUE` VARCHAR(255) DEFAULT NULL,
  4.   `C_ID_FK` BIGINT(20) NOT NULL,
  5.   PRIMARY KEY (`B_ID`),
  6.   KEY `FK_T_TABLE_B_C_ID_FK` (`C_ID_FK`),
  7.   CONSTRAINT `FK_T_TABLE_B_C_ID_FK` FOREIGN KEY (`C_ID_FK`) REFERENCES `T_TABLE_C` (`C_ID`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=latin1

Télécharger

Nous avons bien maintenant la définition de la clé étrangère qui a l’attribut NOT NULL.

 Relation OneToOne bidirectionnelle

Dans le cas précédent nous ne pouvions pas aller d’une instance de C vers B puisque la classe C ne disposait pas d’un attribut de type ClasseB.

Nous allons maintenant définir deux classes D et E de telle manière que nous puissions trouver E quand nous avons D mais aussi l’inverse.

Diagramme de classes

Le code Java

La classe D :

  1. @Table( name = "T_TABLE_D" )
  2. public class ClasseD implements Serializable
  3. {
  4.   @Id
  5.   @GeneratedValue( strategy = GenerationType.IDENTITY )
  6.   @Column( name = "D_ID" )
  7.   private Long id;
  8.  
  9.   @Column( name = "D_REMARQUE" )
  10.   private String remarque;
  11.  
  12.   @OneToOne
  13.   @JoinColumn( name = "E_ID_FK" )
  14.   private ClasseE attributE;

Télécharger

La classe E :

  1. @Table( name = "T_TABLE_E" )
  2. public class ClasseE implements Serializable
  3. {
  4.   @Id
  5.   @GeneratedValue( strategy = GenerationType.IDENTITY )
  6.   @Column( name = "E_ID" )
  7.   private Long id;
  8.  
  9.   private String remarque;
  10.  
  11.   @OneToOne( mappedBy = "attributE" )
  12.   private ClasseD attributD;

Télécharger

Peu de différence entre le code du lien unidirectionnel si ce n’est l’ajout d’un attribut de type ClasseD dans la définition de la classe E.

Tables correspondantes

Table D :

La table E :

Nous pouvons voir que la structure des tables ne change pas dans ce cas là puisqu’en SQL nous ne précisons pas de sens lorsque nous définissons une relation entre 2 tables contrairement à UML.

 Conclusion

Nous venons de voir comment définir une relation OneToOne entre 2 classes persistantes mais dans beaucoup de cas, il pourra être plus judicieux d’embarquer les 2 classes dans une seule table pour des raisons de performances. Vous trouverez dans l’article Deux classes dans une table un exemple concret vous montrant comment utiliser une classe embarquée dans la table de celle à laquelle elle est liée.

Article n° 47

Crée par: chris

Créé le: 19 septembre 2015

Modifié le: 19 septembre 2015

Nombre de visites: 1401

Popularité: 7 %

Popularité absolue: 1

Mots clés de cet article


SPIP

2003-2023 LePpf
Plan du site | | Contact | RSS 2.0 | Sur YouTube

Visiteurs connectés : 0

Nombre moyen de visites quotidiennes sur le site: 196