Tableau des services
Examinons maintenant un autre cas courant - plusieurs à plusieurs. Imaginons que nous ayons une relation plusieurs à plusieurs entre les tâches et les employés :
- Un employé dans la table des employés peut effectuer plusieurs tâches à partir de la table des tâches.
- Une tâche du tableau des tâches peut être attribuée à plusieurs employés.
Cette relation entre entités est appelée plusieurs à plusieurs. Et pour l'implémenter au niveau SQL, nous avons besoin d'une table de service supplémentaire. Appelons-le, par exemple, employee_task.
La table employee_task ne contiendra que deux colonnes :
- id_employé
- id_tâche
Chaque fois que nous attribuons une tâche spécifique à un utilisateur spécifique, une nouvelle ligne sera ajoutée à ce tableau. Exemple:
id_employé | id_tâche |
---|---|
1 | 1 |
1 | 2 |
2 | 3 |
Eh bien, la table des tâches devrait perdre sa colonne employee_id . Cela n'a de sens que si la tâche ne peut être attribuée qu'à un seul employé. Si la tâche peut être affectée à plusieurs employés, ces informations doivent être stockées dans la table de service employee_task .
Relation au niveau de la table
Voici à quoi ressembleront nos nouvelles tables :
identifiant | nom | profession | salaire | âge | join_date |
---|---|---|---|---|---|
1 | Ivanov Ivan | Programmeur | 100000 | 25 | 2012-06-30 |
2 | Petrov Petr | Programmeur | 80000 | 23 | 2013-08-12 |
3 | Ivanov Sergueï | Testeur | 40000 | trente | 2014-01-01 |
4 | Rabinovitch Moisha | Directeur | 200000 | 35 | 2015-05-12 |
5 | Kirienko Anastasia | Responsable administratif | 40000 | 25 | 2015-10-10 |
6 | Vaska | Chat | 1000 | 3 | 2018-11-11 |
Table des employés ( non modifiée ) :
Ce tableau comporte les colonnes suivantes :
- identifiant INT
- nom VARCHAR
- métier VARCHAR
- salaire INT
- âge INT
- join_date DATE
Et voici à quoi ressemble la table des tâches , perdu la colonne employee_id (marquée en rouge):
identifiant | id_employé | nom | date limite |
---|---|---|---|
1 | 1 | Correction d'un bug sur le frontend | 2022-06-01 |
2 | 2 | Correction d'un bug sur le backend | 2022-06-15 |
3 | 5 | Acheter du café | 2022-07-01 |
4 | 5 | Acheter du café | 2022-08-01 |
5 | 5 | Acheter du café | 2022-09-01 |
6 | (NUL) | Nettoyer le bureau | (NUL) |
7 | 4 | Profite de la vie | (NUL) |
8 | 6 | Profite de la vie | (NUL) |
Ce tableau n'a plus que 3 colonnes :
- id - numéro de tâche unique (et lignes du tableau)
- id_employé - (supprimé)
- name - le nom et la description de la tâche
- date limite - l'heure jusqu'à laquelle la tâche doit être terminée
Nous avons également la table de service employee_task , où les données employee_id ont migré de la table des tâches :
id_employé | id_tâche |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
(NUL) | 6 |
4 | 7 |
6 | 8 |
J'ai délibérément enregistré temporairement la colonne supprimée dans la table des tâches afin que vous puissiez voir que les données qu'elle contient ont été déplacées vers la table employee_task.
Un autre point important est la ligne rouge "(NULL) 6" dans la table employee_task. Je l'ai marqué en rouge car il ne sera pas dans la table employee_task .
Si la tâche 7 est affectée à l'utilisateur 4, il doit y avoir une ligne (4, 7) dans la table employee_task.
Si la tâche 6 n'est assignée à personne, il n'y aura simplement aucun enregistrement pour elle dans la table employee_task. Voici à quoi ressembleront les versions finales de ces tableaux :
tableau des tâches :
identifiant | nom | date limite |
---|---|---|
1 | Correction d'un bug sur le frontend | 2022-06-01 |
2 | Correction d'un bug sur le backend | 2022-06-15 |
3 | Acheter du café | 2022-07-01 |
4 | Acheter du café | 2022-08-01 |
5 | Acheter du café | 2022-09-01 |
6 | Nettoyer le bureau | (NUL) |
7 | Profite de la vie | (NUL) |
8 | Profite de la vie | (NUL) |
table employee_task :
id_employé | id_tâche |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
4 | 7 |
6 | 8 |
Communication au niveau de la classe Java
Mais avec la communication au niveau des classes Entity, nous avons un ordre complet. Commençons par la bonne nouvelle.
Tout d'abord, Hibernate a une annotation spéciale @ManyToMany qui vous permet de bien décrire le cas d'une relation de table plusieurs-à-plusieurs.
Deuxièmement, deux classes Entity nous suffisent encore. Nous n'avons pas besoin d'une classe pour la table de service.
Voici à quoi ressembleront nos cours. La classe Employé dans sa forme originale :
@Entity
@Table(name="user")
class Employee {
@Column(name="id")
public Integer id;
@Column(name="name")
public String name;
@Column(name="occupation")
public String occupation;
@Column(name="salary")
public Integer salary;
@Column(name="join_date")
public Date join;
}
Et la classe EmployeeTask dans sa forme originale :
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="deadline")
public Date deadline;
}
Annotation @ManyToMany
J'omettrai les champs existants dans les exemples, mais j'en ajouterai de nouveaux. Voici à quoi ils ressembleront. Classe d'employés :
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="employee_task",
joinColumns= @JoinColumn(name="employee_id", referencedColumnName="id"),
inverseJoinColumns= @JoinColumn(name="task_id", referencedColumnName="id") )
private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();
}
Et la classe EmployeeTask :
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="employee_task",
joinColumns= @JoinColumn(name="task_id", referencedColumnName="id"),
inverseJoinColumns= @JoinColumn(name=" employee_id", referencedColumnName="id") )
private Set<Employee> employees = new HashSet<Employee>();
}
Il paraît que tout est compliqué, mais en fait tout est simple.
Tout d'abord, il utilise l' annotation @JoinTable (à ne pas confondre avec @JoinColumn), qui décrit la table de service employee_task.
Deuxièmement, il décrit que la colonne task_id de la table employee_task fait référence à la colonne id de la table des tâches.
Troisièmement, il indique que la colonne employee_id de la table employee_task fait référence à la colonne id de la table employee.
En fait, à l'aide d'annotations, nous avons décrit quelles données sont contenues dans la table employee_task et comment Hibernate doit les interpréter.
Mais maintenant, nous pouvons très facilement ajouter (et supprimer) une tâche à n'importe quel employé. Et ajoutez également n'importe quel interprète à n'importe quelle tâche.
Demander des exemples
Écrivons quelques requêtes intéressantes pour mieux comprendre le fonctionnement de ces champs ManyToMany. Et ils fonctionnent exactement comme prévu.
Tout d'abord, notre ancien code fonctionnera sans changement, puisque le directeur avait auparavant un champ tâches :
EmployeeTask task1 = new EmployeeTask();
task1.description = "Do Something Important";
session.persist(task1);
EmployeeTask task2 = new EmployeeTask();
task2.description = "Nothing to do";
session.persist(task2);
session.flush();
Employee director = session.find(Employee.class, 4);
director.tasks.add(task1);
director.tasks.add(task2);
session.update(director);
session.flush();
Deuxièmement, si nous voulons affecter un autre interprète à une tâche, il est encore plus facile de le faire :
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);
session.update(task);
session.flush();
Important! À la suite de l'exécution de cette demande, non seulement la tâche aura un exécuteur-directeur, mais également le directeur aura la tâche n ° 101.
Tout d'abord, le fait concernant la relation entre le directeur et la tâche dans la table employee_task sera stocké sous forme de chaîne : (4,101).
Deuxièmement, les champs marqués d'annotations @ManyToMany sont des objets proxy, et lorsqu'on y accède, une requête de base de données est toujours exécutée.
Ainsi, si vous ajoutez une tâche à un employé et enregistrez des informations sur l'employé dans la base de données, la tâche aura ensuite un nouvel exécuteur dans la liste des exécuteurs.
GO TO FULL VERSION