6.1 Gestion des dépendances profondes

Et quelques choses plus utiles et intéressantes sur les annotations @OneToMany et autres. Ils ont tous 4 options couramment utilisées :

  • cascade = CascadeType.ALL
  • orphanRemoval = vrai
  • récupérer = FetchType.LAZY

Nous allons maintenant les analyser plus en détail. Et nous commencerons par le plus intéressant - CascadeType . Ce paramètre détermine ce qui doit arriver aux entités dépendantes si nous changeons l'entité principale.

La spécification JPA a les valeurs suivantes pour ce paramètre :

  • TOUS
  • PERSISTER
  • FUSIONNER
  • RETIRER
  • RAFRAÎCHIR
  • DÉTACHER

Cependant, Hibernate étend cette spécification à trois options supplémentaires :

  • REPRODUIRE
  • SAVE_UPDATE
  • SERRURE

Il y a, bien sûr, un parallèle fort avec la base de données et leur CONSTRANIS. Cependant, il existe également des différences. Hibernate essaie de cacher le travail réel avec la base de données autant que possible, donc ces cascades Hibernate concernent exactement les objets Entity.

6.2 CascadeType

Le paramètre cascade décrit ce qui doit arriver aux objets dépendants si nous changeons leur parent (objet maître). Le plus souvent, ce paramètre est utilisé avec des annotations qui décrivent les dépendances d'objet :

Exemple:

OneToOne(cascade = CascadeType.ALL)

Ou comme ceci :

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})

Il peut également être écrit sous la forme d'une annotation distincte :

@Cascade({ org.hibernate.annotations.CascadeType.ALL })

Parlons maintenant de la signification de ces annotations.

6.3 TOUT, PERSISTER, FUSIONNER

CascadeType.ALLsignifie que toutes les actions que nous effectuons avec l'objet parent doivent être répétées pour ses objets dépendants.

CascadeType.PERSISTsignifie que si nous enregistrons l'objet parent dans la base de données, la même chose doit être faite avec ses objets dépendants. Exemple:


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

Un exemple de travail avec cette classe :


Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
 
session.persist(director);
session.flush();

Nous enregistrons uniquement un objet de type Employee, son objet dépendant EmployeeTask sera automatiquement enregistré dans la base de données.

CascadeType.MERGEsignifie que si nous mettons à jour l'objet parent dans la base de données, la même chose doit être faite avec ses objets dépendants.

6.4 RETIRER, SUPPRIMER, DÉTACHER

CascadeType.REMOVEsignifie que si nous supprimons un objet parent dans la base de données, la même chose doit être faite avec ses objets dépendants.

CascadeType.DELETEsignifie la même chose. Ce sont des synonymes. Juste à partir de spécifications différentes.

CascadeType.DETACHsignifie que si nous supprimons l'objet parent de la session, la même chose doit être faite avec ses objets dépendants. Exemple:


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

Un exemple de travail avec cette classe :


Employee director = new Employee();
EmployeeTask task = new EmployeeTask();
director.task = task;
director.task = task;
session.flush();
 
assertThat(session.contains(director)).isTrue();
assertThat(session.contains(task)).isTrue();
 
session.detach(director);
 
assertThat(session.contains(director)).isFalse();
assertThat(session.contains(task)).isFalse();

CascadeType.REFRESHet CascadeType.SAVE_UPDATEfonctionnent de la même manière que prévu - ils dupliquent les actions qui sont effectuées avec l'objet parent vers son objet dépendant.

6.5 Option de suppression des orphelins

Parfois aussi, vous pouvez rencontrer le paramètre orphan. C'est l'abréviation de suppression des orphelins. Il est utilisé pour s'assurer qu'il n'y a pas d'entité enfant sans entité parent.

OneToOne(orphan = true)

Si ce paramètre est défini sur true, alors l'entité enfant sera supprimée si elle a disparutous les liens. Ce n'est pas exactement la même chose que Cascade.REMOVE.

Vous pouvez avoir une situation où plusieurs entités parent font référence à un enfant. Il est alors avantageux qu'elle ne soit pas supprimée avec la suppression de l'entité parente, mais uniquement si toutes les références à celle-ci sont annulées.

Disons que vous avez une classe :


@Entity
@Table(name="user")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToMany(cascade = CascadeType.ALL, orphan = true)
   @JoinColumn(name = "employee_id")
   private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();
}


Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.tasks.get(0);
director.tasks.remove(task)
session.persist(director);
session.flush();

L'objet EmployeeTask sera supprimé car il ne reste aucune référence à celui-ci. En même temps, personne n'a supprimé l'objet parent.

6.6 option de récupération

L'option de récupération vous permet de contrôler la façon dont les objets dépendants sont chargés. Il prend généralement l'une des deux valeurs suivantes :

  • FetchType.LAZY
  • FetchType.EAGER

C'est un sujet très intéressant avec divers pièges, donc je ferais mieux d'en parler dans une conférence séparée.