Servicebord

Lad os nu se på et andet almindeligt tilfælde - mange-til-mange. Lad os forestille os, at vi har et mange-til-mange forhold mellem opgaver og medarbejdere :

  • En medarbejder i medarbejdertabellen kan udføre mange opgaver fra opgavetabellen.
  • Én opgave i opgavetabellen kan tildeles flere medarbejdere.

Dette forhold mellem enheder kaldes mange-til-mange. Og for at implementere det på SQL-niveau har vi brug for en ekstra servicetabel. Lad os kalde det for eksempel medarbejder_opgave.

Tabellen medarbejder_opgave vil kun indeholde to kolonner:

  • Medarbejder-ID
  • opgave-id

Hver gang vi tildeler en bestemt opgave til en bestemt bruger, vil en ny række blive tilføjet til denne tabel. Eksempel:

Medarbejder-ID opgave-id
1 1
1 2
2 3

Nå, opgavetabellen burde miste sin werknemer_id-kolonne . Det giver kun mening, hvis opgaven kun kan tildeles én medarbejder. Hvis opgaven kan tildeles flere medarbejdere, så skal denne information gemmes i medarbejder_opgave-servicetabellen .

Relation på tabelniveau

Sådan kommer vores nye borde til at se ud:

id navn beskæftigelse løn alder join_date
1 Ivanov Ivan Programmer 100.000 25 2012-06-30
2 Petrov Petr Programmer 80.000 23 2013-08-12
3 Ivanov Sergey Tester 40.000 tredive 2014-01-01
4 Rabinovich Moisha Direktør 200.000 35 2015-05-12
5 Kirienko Anastasia Kontorchef 40.000 25 2015-10-10
6 Vaska Kat 1000 3 2018-11-11

Medarbejdertabel ( ikke ændret ) :

Denne tabel har følgende kolonner:

  • id INT
  • navn VARCHAR
  • erhverv VARCHAR
  • løn INT
  • alder INT
  • join_date DATE

Og sådan ser opgavetabellen ud , mistede kolonnen medarbejder_id (markeret med rødt):

id emploee_id navn deadline
1 1 Ret en fejl på frontend 2022-06-01
2 2 Ret en fejl på backend 2022-06-15
3 5 Køb kaffe 2022-07-01
4 5 Køb kaffe 2022-08-01
5 5 Køb kaffe 2022-09-01
6 (NUL) Ryd op på kontoret (NUL)
7 4 Nyd livet (NUL)
8 6 Nyd livet (NUL)

Denne tabel har nu kun 3 kolonner:

  • id - unikt opgavenummer (og rækker i tabellen)
  • medarbejder-id - (fjernet)
  • navn - navnet og beskrivelsen af ​​opgaven
  • deadline - det tidspunkt, hvortil opgaven skal udføres

Vi har også tjenestetabellen medarbejder_opgave , hvor medarbejder_id-data er migreret fra opgavetabellen:

Medarbejder-ID opgave-id
1 1
2 2
5 3
5 4
5 5
(NUL) 6
4 7
6 8

Jeg har med vilje midlertidigt gemt den slettede kolonne i opgavetabellen, så du kan se, at dataene fra den er flyttet til tabellen medarbejder_opgave.

Et andet vigtigt punkt er den røde linje "(NULL) 6" i tabellen medarbejder_opgave. Jeg har markeret det med rødt, fordi det ikke vil være i tabellen medarbejder_opgave .

Hvis opgave 7 er tildelt bruger 4, så skal der være en række (4, 7) i tabellen medarbejder_opgave.

Hvis opgave 6 ikke er tildelt nogen, så vil der simpelthen ikke være nogen post for den i tabellen medarbejder_opgave. Sådan ser de endelige versioner af disse tabeller ud:

opgave tabel :

id navn deadline
1 Ret en fejl på frontend 2022-06-01
2 Ret en fejl på backend 2022-06-15
3 Køb kaffe 2022-07-01
4 Køb kaffe 2022-08-01
5 Køb kaffe 2022-09-01
6 Ryd op på kontoret (NUL)
7 Nyd livet (NUL)
8 Nyd livet (NUL)

medarbejder_opgave tabel:

Medarbejder-ID opgave-id
1 1
2 2
5 3
5 4
5 5
4 7
6 8

Kommunikation på Java-klasseniveau

Men med kommunikation på niveau med enhedsklasser har vi en komplet orden. Lad os starte med de gode nyheder.

For det første har Hibernate en speciel @ManyToMany- annotation , der giver dig mulighed for godt at beskrive tilfældet med et mange-til-mange-tabellforhold.

For det andet er to Entity-klasser stadig nok for os. Vi behøver ikke en klasse til servicebordet.

Sådan ser vores klasser ud. Medarbejderklassen i sin oprindelige 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 oprindelige 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 annotation

Jeg vil udelade de eksisterende felter i eksemplerne, men jeg tilføjer nye. Her er, hvordan de kommer til at se ud. Medarbejderklasse : _

@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 ud til, at alt er kompliceret, men faktisk er alt enkelt.

For det første bruger den @JoinTable- annotationen (ikke at forveksle med @JoinColumn), som beskriver medarbejder_task-tjenestetabellen.

For det andet beskriver den, at opgave_id-kolonnen i tabellen medarbejder_opgave refererer til id-kolonnen i opgavetabellen.

For det tredje står der, at kolonnen werknemer_id i tabellen medarbejder_opgave refererer til id kolonnen i tabellen medarbejder.

Faktisk beskrev vi ved hjælp af annoteringer, hvilke data der er indeholdt i werknemer_task-tabellen, og hvordan Hibernate skal fortolke dem.

Men nu kan vi meget nemt tilføje (og slette) en opgave til enhver medarbejder. Og føj også enhver kunstner til enhver opgave.

Anmod om eksempler

Lad os skrive et par interessante forespørgsler for bedre at forstå, hvordan disse ManyToMany-felter fungerer. Og de fungerer præcis som forventet.

For det første vil vores gamle kode fungere uden ændringer, da direktøren havde et opgavefelt 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 andet, hvis vi ønsker at tildele en anden performer til en opgave, så er det endnu nemmere at gø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();

Vigtig! Som følge af udførelse af denne anmodning vil ikke kun opgaven have en bobestyrer-direktør, men også direktøren vil have opgave nr. 101.

Først vil kendsgerningen om forholdet mellem direktøren og opgaven i tabellen medarbejder_opgave blive gemt som en streng: (4.101).

For det andet er felterne markeret med @ManyToMany- annoteringer proxy-objekter, og når de tilgås, udføres der altid en databaseforespørgsel.

Så hvis du tilføjer en opgave til en medarbejder og gemmer oplysninger om medarbejderen i databasen, så får opgaven herefter en ny udfører på listen over udførende.