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.ALL
signifie que toutes les actions que nous effectuons avec l'objet parent doivent être répétées pour ses objets dépendants.
CascadeType.PERSIST
signifie 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.MERGE
signifie 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.REMOVE
signifie 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.DELETE
signifie la même chose. Ce sont des synonymes. Juste à partir de spécifications différentes.
CascadeType.DETACH
signifie 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.REFRESH
et CascadeType.SAVE_UPDATE
fonctionnent 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.
GO TO FULL VERSION