5.1 Diverses formes de communication en tête-à-tête

Il existe un autre cas intéressant et plutôt spécifique de relation entre deux classes Entity - une relation un-à-un.

J'appelle ce cas très spécifique, car il s'agit plus d'objets Java que d'une base de données. Dans la base de données, il n'y a que deux options pour la relation entre les tables :

  • La ligne de la table contient un lien vers l'ID d'une autre table.
  • La table de service est utilisée pour les relations plusieurs-à-plusieurs.

Dans le cas des classes Entity, il peut y avoir des options décrites par plusieurs annotations :

  • @Embarqué
  • OneToOne unilatéral
  • Bilatéral OneToOne
  • @MapsId

Ci-dessous, nous examinerons les plus populaires d'entre eux.

5.2 Intégré

Soit dit en passant, nous avons déjà envisagé l' option de communication individuelle@Embedded la plus simple - il s'agit d'une annotation . Dans ce cas, nous avons deux classes stockées dans la même table de la base de données.

Disons que nous voulons stocker l'adresse de l'utilisateur dans la classe UserAddress :


@Embeddable
class UserAddress {
   @Column(name="user_address_country")
   public String country;
   @Column(name="user_address_city")
   public String city;
   @Column(name="user_address_street")
   public String street;
   @Column(name="user_address_home")
   public String home;
}

Il suffit ensuite d'ajouter un champ avec cette adresse à la classe User :


@Entity
@Table(name="user")
class User {
   @Column(name="id")
   public Integer id;
 
   @Embedded
   public UserAddress address;
 
   @Column(name="created_date")
   public Date createdDate;
}

Hibernate fera le reste : les données seront stockées dans une seule table, mais lors de l'écriture de requêtes HQL, vous devrez opérer sur des champs de classe.

Exemple de requête HQL :

select from User where address.city = 'Paris'

5.3 OneToOne unilatéral

Imaginez maintenant la situation : nous avons une table source employee et une tâche qui fait référence à employee. Mais nous savons avec certitude qu'un maximum d'une tâche peut être assigné à un utilisateur. Ensuite, nous pouvons utiliser l'annotation pour décrire cette situation @OneToOne.

Exemple:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
   @OneToOne
   @JoinColumn(name = "employee_id")
   public Employee employee;
 
   @Column(name="deadline")
   public Date deadline;
}

Hibernate s'assurera que non seulement une tâche a un utilisateur, mais aussi qu'un utilisateur n'a qu'une seule tâche. Sinon, ce cas n'est pratiquement pas différent de @ManyToOne.

5.4 Bilatéral OneToOne

L'option précédente peut être un peu gênante, car souvent vous souhaitez affecter un employé non seulement à une tâche, mais également affecter une tâche à un employé.

Pour ce faire, vous pouvez ajouter le champ EmployeeTask à la classe Employee et lui donner les annotations correctes.


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
   private EmployeeTask task;
}

Important!La table des employés n'a pas de champ task_id , à la place le champ employee_id de la table des tâches est utilisé pour établir une relation entre les tables .

L'établissement d'une connexion entre des objets ressemble à ceci :


Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employee = director;
director.task = task;
 
session.update(task);
session.flush();

Pour supprimer le lien, les liens doivent également être supprimés des deux objets :


Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.task;
 
task.employee = null;
session.update(task);
 
director.task = null;
session.update(director);
 
session.flush();