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.