Servicebord
La oss nå se på et annet vanlig tilfelle - mange-til-mange. La oss forestille oss at vi har et mange-til-mange forhold mellom oppgaver og ansatte :
- En ansatt i ansatttabellen kan gjøre mange oppgaver fra oppgavetabellen.
- Én oppgave i oppgavetabellen kan tildeles flere ansatte.
Dette forholdet mellom enheter kalles mange-til-mange. Og for å implementere det på SQL-nivå, trenger vi en ekstra servicetabell. La oss kalle det for eksempel ansatt_oppgave.
Employer_task-tabellen vil kun inneholde to kolonner:
- Ansatt ID
- task_id
Hver gang vi tildeler en spesifikk oppgave til en bestemt bruker, vil en ny rad bli lagt til denne tabellen. Eksempel:
Ansatt ID | task_id |
---|---|
1 | 1 |
1 | 2 |
2 | 3 |
Vel, oppgavetabellen skal miste kolonnen medarbeider-id . Det gir mening bare hvis oppgaven bare kan tildeles én ansatt. Hvis oppgaven kan tildeles flere ansatte, må denne informasjonen lagres i tjenestetabellen for ansatte_oppgave .
Forhold på tabellnivå
Slik vil de nye bordene våre se ut:
id | Navn | okkupasjon | lønn | alder | join_date |
---|---|---|---|---|---|
1 | Ivanov Ivan | Programmerer | 100 000 | 25 | 2012-06-30 |
2 | Petrov Petr | Programmerer | 80 000 | 23 | 2013-08-12 |
3 | Ivanov Sergey | Tester | 40 000 | tretti | 2014-01-01 |
4 | Rabinovich Moisha | Regissør | 200 000 | 35 | 2015-05-12 |
5 | Kirienko Anastasia | Kontorsjef | 40 000 | 25 | 2015-10-10 |
6 | Vaska | Katt | 1000 | 3 | 2018-11-11 |
Ansatttabell ( ikke endret ) :
Denne tabellen har følgende kolonner:
- ID INT
- navn VARCHAR
- yrke VARCHAR
- lønn INT
- alder INT
- join_date DATE
Og slik ser oppgavetabellen ut , mistet kolonnen for ansatte_id (merket med rødt):
id | emploee_id | Navn | frist |
---|---|---|---|
1 | 1 | Rett opp en feil på frontend | 2022-06-01 |
2 | 2 | Rett opp en feil på backend | 2022-06-15 |
3 | 5 | Kjøp kaffe | 2022-07-01 |
4 | 5 | Kjøp kaffe | 2022-08-01 |
5 | 5 | Kjøp kaffe | 2022-09-01 |
6 | (NULL) | Rydd opp på kontoret | (NULL) |
7 | 4 | Nyt livet | (NULL) |
8 | 6 | Nyt livet | (NULL) |
Denne tabellen har nå bare 3 kolonner:
- id - unikt oppgavenummer (og rader i tabellen)
- ansatt_id - (fjernet)
- navn - navnet og beskrivelsen av oppgaven
- deadline - tidspunktet oppgaven må være utført til
Vi har også ansatt_oppgave-tjenestetabellen , der ansatt_id-data har migrert fra oppgavetabellen:
Ansatt ID | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
(NULL) | 6 |
4 | 7 |
6 | 8 |
Jeg har med vilje midlertidig lagret den slettede kolonnen i oppgavetabellen slik at du kan se at dataene fra den har flyttet til tabellen medarbeider_oppgave.
Et annet viktig punkt er den røde linjen "(NULL) 6" i tabellen medarbeider_oppgave. Jeg har merket den med rødt fordi den ikke vil være i tabellen medarbeider_oppgave .
Hvis oppgave 7 er tilordnet bruker 4, bør det være en rad (4, 7) i tabellen ansatt_oppgave.
Hvis oppgave 6 ikke er tildelt noen, vil det rett og slett ikke være noen post for den i tabellen medarbeider_oppgave. Slik vil de endelige versjonene av disse tabellene se ut:
oppgavetabell :
id | Navn | frist |
---|---|---|
1 | Rett opp en feil på frontend | 2022-06-01 |
2 | Rett opp en feil på backend | 2022-06-15 |
3 | Kjøp kaffe | 2022-07-01 |
4 | Kjøp kaffe | 2022-08-01 |
5 | Kjøp kaffe | 2022-09-01 |
6 | Rydd opp på kontoret | (NULL) |
7 | Nyt livet | (NULL) |
8 | Nyt livet | (NULL) |
ansatt_oppgavetabell:
Ansatt ID | task_id |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
4 | 7 |
6 | 8 |
Kommunikasjon på Java-klassenivå
Men med kommunikasjon på nivå med Entity-klasser har vi en fullstendig orden. La oss starte med de gode nyhetene.
For det første har Hibernate en spesiell @ManyToMany- annotering som lar deg beskrive tilfellet med et mange-til-mange-tabellforhold.
For det andre er to Entity-klasser fortsatt nok for oss. Vi trenger ikke en klasse for servicebordet.
Slik vil klassene våre se ut. Ansatte- klassen i sin opprinnelige form:
@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;
}
Og EmployeeTask- klassen i sin opprinnelige form:
@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-kommentar
Jeg vil utelate de eksisterende feltene i eksemplene, men jeg vil legge til nye. Her er hvordan de vil se ut. Ansatt 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>();
}
Og EmployeeTask- klassen :
@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>();
}
Det ser ut til at alt er komplisert, men faktisk er alt enkelt.
Først bruker den @JoinTable -kommentaren (må ikke forveksles med @JoinColumn), som beskriver tjenestetabellen for ansatte_oppgave.
For det andre beskriver den at task_id-kolonnen i tabellen medarbeider_oppgave refererer til id-kolonnen i oppgavetabellen.
For det tredje står det at ansatt_id-kolonnen i ansattoppgavetabellen refererer til id-kolonnen i ansatttabellen.
Faktisk, ved hjelp av merknader, beskrev vi hvilke data som finnes i tabellen medarbeider_oppgave og hvordan Hibernate skal tolke den.
Men nå kan vi veldig enkelt legge til (og slette) en oppgave til enhver ansatt. Og legg også til enhver utøver til enhver oppgave.
Be om eksempler
La oss skrive et par interessante spørsmål for å bedre forstå hvordan disse ManyToMany-feltene fungerer. Og de fungerer akkurat som forventet.
For det første vil vår gamle kode fungere uten endringer, siden direktøren hadde et oppgavefelt før:
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();
For det andre, hvis vi ønsker å tilordne en annen utøver til en oppgave, er det enda enklere å gjøre dette:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);
session.update(task);
session.flush();
Viktig! Som et resultat av å utføre denne forespørselen vil ikke bare oppgaven ha en eksekutør-direktør, men også direktøren vil ha oppgave nr. 101.
Først vil fakta om forholdet mellom direktøren og oppgaven i tabellen ansatt_oppgave bli lagret som en streng: (4,101).
For det andre er feltene merket med @ManyToMany- annoteringer proxy-objekter, og når de åpnes, blir det alltid utført en databasespørring.
Så hvis du legger til en oppgave til en ansatt og lagrer informasjon om den ansatte i databasen, vil oppgaven etter det ha en ny utfører i listen over utførende.