Service tafel
Laten we nu eens kijken naar een ander veelvoorkomend geval: veel-op-veel. Laten we ons voorstellen dat we een veel-op-veel- relatie hebben tussen taken en werknemers :
- Eén medewerker in de medewerkerstabel kan veel taken uitvoeren vanuit de takentabel.
- Eén taak in de takentabel kan aan meerdere medewerkers worden toegewezen.
Deze relatie tussen entiteiten wordt veel-op-veel genoemd. En om het op SQL-niveau te implementeren, hebben we een extra servicetabel nodig. Laten we het bijvoorbeeld werknemer_taak noemen.
De tabel employee_task bevat slechts twee kolommen:
- medewerker_id
- taak_id
Elke keer dat we een specifieke taak aan een specifieke gebruiker toewijzen, wordt er een nieuwe rij aan deze tabel toegevoegd. Voorbeeld:
medewerker_id | taak_id |
---|---|
1 | 1 |
1 | 2 |
2 | 3 |
Welnu, de taaktabel zou zijn kolom employee_id moeten verliezen . Het heeft alleen zin als de taak maar aan één medewerker kan worden toegewezen. Als de taak aan meerdere medewerkers kan worden toegewezen, moet deze informatie worden opgeslagen in de servicetabel employee_task .
Relatie op tafelniveau
Zo zien onze nieuwe tafels eruit:
ID kaart | naam | bezigheid | salaris | leeftijd | join_date |
---|---|---|---|---|---|
1 | Ivanov Ivan | Programmeur | 100000 | 25 | 2012-06-30 |
2 | Petrov Petr | Programmeur | 80000 | 23 | 2013-08-12 |
3 | Ivanov Sergej | Tester | 40000 | dertig | 01-01-2014 |
4 | Rabinovich Moisha | Regisseur | 200000 | 35 | 2015-05-12 |
5 | Kirienko Anastasia | Officemanager | 40000 | 25 | 2015-10-10 |
6 | Vaska | Kat | 1000 | 3 | 2018-11-11 |
Werknemerstabel ( niet gewijzigd ) :
Deze tabel heeft de volgende kolommen:
- id INT
- naam VARCHAR
- bezetting VARCHAR
- salaris INT
- leeftijd INT
- join_date DATUM
En zo ziet de taaktabel eruit , de kolom employee_id verloren (rood gemarkeerd):
ID kaart | medewerker_id | naam | deadline |
---|---|---|---|
1 | 1 | Los een bug op de frontend op | 01-06-2022 |
2 | 2 | Los een bug op de backend op | 2022-06-15 |
3 | 5 | Koop koffie | 01-07-2022 |
4 | 5 | Koop koffie | 01-08-2022 |
5 | 5 | Koop koffie | 01-09-2022 |
6 | (NUL) | Ruim het kantoor op | (NUL) |
7 | 4 | Geniet van het leven | (NUL) |
8 | 6 | Geniet van het leven | (NUL) |
Deze tabel heeft nu slechts 3 kolommen:
- id - uniek taaknummer (en rijen in de tabel)
- werknemer_id - (verwijderd)
- naam - de naam en beschrijving van de taak
- deadline - de tijd tot wanneer de taak moet worden voltooid
We hebben ook de employee_task-servicetabel , waar de employee_id-gegevens zijn gemigreerd vanuit de taaktabel:
medewerker_id | taak_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
(NUL) | 6 |
4 | 7 |
6 | 8 |
Ik heb met opzet de verwijderde kolom tijdelijk in de taaktabel opgeslagen, zodat u kunt zien dat de gegevens ervan zijn verplaatst naar de tabel employee_task.
Een ander belangrijk punt is de rode lijn "(NULL) 6" in de tabel employee_task. Ik heb het rood gemarkeerd omdat het niet in de tabel employee_task staat .
Als taak 7 is toegewezen aan gebruiker 4, moet er een rij (4, 7) zijn in de tabel employee_task.
Als taak 6 aan niemand is toegewezen, is er simpelweg geen record voor in de tabel employee_task. Dit is hoe de definitieve versies van deze tabellen eruit zullen zien:
taak tabel :
ID kaart | naam | deadline |
---|---|---|
1 | Los een bug op de frontend op | 01-06-2022 |
2 | Los een bug op de backend op | 2022-06-15 |
3 | Koop koffie | 01-07-2022 |
4 | Koop koffie | 01-08-2022 |
5 | Koop koffie | 01-09-2022 |
6 | Ruim het kantoor op | (NUL) |
7 | Geniet van het leven | (NUL) |
8 | Geniet van het leven | (NUL) |
tabel werknemer_taak:
medewerker_id | taak_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
4 | 7 |
6 | 8 |
Communicatie op het niveau van de Java-klasse
Maar met communicatie op het niveau van Entity-klassen hebben we een complete bestelling. Laten we beginnen met het goede nieuws.
Ten eerste heeft Hibernate een speciale @ManyToMany- annotatie waarmee u het geval van een veel-op-veel-tabelrelatie goed kunt beschrijven.
Ten tweede zijn twee Entity-klassen nog steeds genoeg voor ons. We hebben geen klasse nodig voor de servicetafel.
Zo zien onze lessen eruit. De klasse Employee in zijn oorspronkelijke vorm:
@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;
}
En de klasse EmployeeTask in zijn oorspronkelijke vorm:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="deadline")
public Date deadline;
}
@ManyToMany-annotatie
Ik zal de bestaande velden in de voorbeelden weglaten, maar ik zal nieuwe toevoegen. Hier is hoe ze eruit zullen zien. Werknemer klasse :
@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>();
}
En de EmployeeTask -klasse :
@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>();
}
Het lijkt erop dat alles ingewikkeld is, maar in feite is alles eenvoudig.
Ten eerste gebruikt het de annotatie @JoinTable (niet te verwarren met @JoinColumn), die de servicetabel employee_task beschrijft.
Ten tweede beschrijft het dat de kolom task_id van de tabel employee_task verwijst naar de kolom id van de taaktabel.
Ten derde staat er dat de kolom employee_id van de tabel employee_task verwijst naar de kolom id van de werknemerstabel.
Met behulp van annotaties hebben we zelfs beschreven welke gegevens in de tabel employee_task staan en hoe Hibernate deze moet interpreteren.
Maar nu kunnen we heel eenvoudig een taak toevoegen (en verwijderen) aan elke medewerker. En voeg ook elke artiest toe aan elke taak.
Vraag voorbeelden aan
Laten we een paar interessante vragen schrijven om beter te begrijpen hoe deze ManyToMany-velden werken. En ze werken precies zoals verwacht.
Ten eerste zal onze oude code zonder wijzigingen werken, aangezien de directeur eerder een takenveld had:
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();
Ten tweede, als we een andere artiest aan een bepaalde taak willen toewijzen, dan is het nog eenvoudiger om dit te doen:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);
session.update(task);
session.flush();
Belangrijk! Door uitvoering van dit verzoek krijgt niet alleen de taak een uitvoerder-directeur, maar krijgt ook de directeur taak nr. 101.
Eerst wordt het feit over de relatie tussen de directeur en de taak in de tabel employee_task opgeslagen als een string: (4,101).
Ten tweede zijn de velden gemarkeerd met @ManyToMany- annotaties proxy-objecten en wanneer ze worden geopend, wordt er altijd een databasequery uitgevoerd.
Dus als je een taak toevoegt aan een medewerker en informatie over de medewerker opslaat in de database, dan krijgt de taak daarna een nieuwe uitvoerder in de lijst met uitvoerders.