Service table

Ngayon tingnan natin ang isa pang karaniwang kaso - many-to-many. Isipin natin na mayroon tayong maraming-sa-maraming ugnayan sa pagitan ng mga gawain at empleyado :

  • Ang isang empleyado sa talahanayan ng empleyado ay maaaring gumawa ng maraming gawain mula sa talahanayan ng gawain.
  • Ang isang gawain sa talahanayan ng gawain ay maaaring italaga sa ilang empleyado.

Ang ugnayang ito sa pagitan ng mga entity ay tinatawag na many-to-many. At para maipatupad ito sa antas ng SQL, kailangan namin ng karagdagang talahanayan ng serbisyo. Tawagan natin ito, halimbawa, employee_task.

Ang talahanayan ng employee_task ay maglalaman lamang ng dalawang column:

  • employee_id
  • task_id

Sa bawat oras na magtatalaga kami ng isang partikular na gawain sa isang partikular na user, isang bagong row ang idaragdag sa talahanayang ito. Halimbawa:

employee_id task_id
1 1
1 2
2 3

Well, dapat mawala sa talahanayan ng gawain ang column na employee_id . Makatuwiran lamang kung ang gawain ay maaari lamang italaga sa isang empleyado. Kung ang gawain ay maaaring italaga sa ilang empleyado, ang impormasyong ito ay dapat na naka-imbak sa employee_task service table .

Relasyon sa Antas ng Talahanayan

Narito ang magiging hitsura ng aming mga bagong talahanayan:

id pangalan hanapbuhay suweldo edad Sumali sa date
1 Ivanov Ivan Programmer 100000 25 2012-06-30
2 Petrov Petr Programmer 80000 23 2013-08-12
3 Ivanov Sergey Tester 40000 tatlumpu 2014-01-01
4 Rabinovich Moisha Direktor 200000 35 2015-05-12
5 Kirienko Anastasia Tagapamahala ng Opisina 40000 25 2015-10-10
6 Vaska Pusa 1000 3 2018-11-11

Talaan ng empleyado ( hindi binago ) :

Ang talahanayang ito ay may mga sumusunod na column:

  • id INT
  • pangalan VARCHAR
  • hanapbuhay VARCHAR
  • suweldo INT
  • edad INT
  • join_date DATE

At ganito ang hitsura ng talahanayan ng gawain , nawala ang column na employee_id (minarkahan ng pula):

id emploee_id pangalan deadline
1 1 Ayusin ang isang bug sa frontend 2022-06-01
2 2 Ayusin ang isang bug sa backend 2022-06-15
3 5 Bumili ng kape 2022-07-01
4 5 Bumili ng kape 2022-08-01
5 5 Bumili ng kape 2022-09-01
6 (WALA) Linisin ang opisina (WALA)
7 4 Masiyahan sa buhay (WALA)
8 6 Masiyahan sa buhay (WALA)

May 3 column na lang ang talahanayang ito:

  • id - natatanging numero ng gawain (at mga hilera sa talahanayan)
  • employee_id - (inalis)
  • pangalan - ang pangalan at paglalarawan ng gawain
  • deadline - ang oras kung kailan dapat makumpleto ang gawain

Mayroon din kaming employee_task service table , kung saan ang employee_id data ay lumipat mula sa task table:

employee_id task_id
1 1
2 2
5 3
5 4
5 5
(WALA) 6
4 7
6 8

Sinadya kong pansamantalang i-save ang tinanggal na column sa task table para makita mo na ang data mula dito ay lumipat sa employee_task table.

Ang isa pang mahalagang punto ay ang pulang linya na "(NULL) 6" sa talahanayan ng empleyado_task. Minarkahan ko ito ng pula dahil wala ito sa employee_task table .

Kung ang gawain 7 ay itinalaga sa user 4, dapat mayroong isang hilera (4, 7) sa talahanayan ng empleyado_task.

Kung ang gawain 6 ay hindi itinalaga sa sinuman, pagkatapos ay walang rekord para dito sa talahanayan ng empleyado_task. Narito ang magiging hitsura ng mga huling bersyon ng mga talahanayang ito:

talahanayan ng gawain :

id pangalan deadline
1 Ayusin ang isang bug sa frontend 2022-06-01
2 Ayusin ang isang bug sa backend 2022-06-15
3 Bumili ng kape 2022-07-01
4 Bumili ng kape 2022-08-01
5 Bumili ng kape 2022-09-01
6 Linisin ang opisina (WALA)
7 Masiyahan sa buhay (WALA)
8 Masiyahan sa buhay (WALA)

talahanayan ng employee_task:

employee_id task_id
1 1
2 2
5 3
5 4
5 5
4 7
6 8

Komunikasyon sa antas ng klase ng Java

Ngunit sa komunikasyon sa antas ng Entity-classes, mayroon kaming kumpletong order. Magsimula tayo sa mabuting balita.

Una, ang Hibernate ay may espesyal na @ManyToMany annotation na nagbibigay-daan sa iyong mahusay na ilarawan ang kaso ng isang many-to-many table relationship.

Pangalawa, sapat pa sa amin ang dalawang klase ng Entity. Hindi namin kailangan ng klase para sa table ng serbisyo.

Narito ang magiging hitsura ng aming mga klase. Ang klase ng Empleyado sa orihinal nitong anyo:

@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;
}

At ang klase ng EmployeeTask sa orihinal nitong anyo:

@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

Aalisin ko ang mga umiiral na field sa mga halimbawa, ngunit magdadagdag ako ng mga bago. Narito ang magiging hitsura nila. Klase ng empleyado :

@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>();

}

At ang klase ng 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>();

}

Tila ang lahat ay kumplikado, ngunit sa katunayan ang lahat ay simple.

Una, ginagamit nito ang @JoinTable annotation (hindi dapat ipagkamali sa @JoinColumn), na naglalarawan sa employee_task service table.

Pangalawa, inilalarawan nito na ang task_id column ng employee_task table ay tumutukoy sa id column ng task table.

Pangatlo, sinasabi nito na ang employee_id column ng employee_task table ay tumutukoy sa id column ng employee table.

Sa katunayan, sa tulong ng mga anotasyon, inilarawan namin kung anong data ang nilalaman sa talahanayan ng employee_task at kung paano ito dapat bigyang-kahulugan ng Hibernate.

Ngunit ngayon ay napakadali na nating magdagdag (at magtanggal) ng isang gawain sa sinumang empleyado. At magdagdag din ng sinumang tagapalabas sa anumang gawain.

Humiling ng mga halimbawa

Sumulat tayo ng ilang kawili-wiling mga query para mas maunawaan kung paano gumagana ang mga field na ito ng ManyToMany. At gumagana ang mga ito nang eksakto tulad ng inaasahan.

Una, ang aming lumang code ay gagana nang walang mga pagbabago, dahil ang direktor ay may field ng mga gawain bago:

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();

Pangalawa, kung gusto nating magtalaga ng isa pang tagapalabas sa ilang gawain, kung gayon mas madaling gawin ito:

Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);

session.update(task);
session.flush();

Mahalaga! Bilang resulta ng pagpapatupad ng kahilingang ito, hindi lamang ang gawain ay magkakaroon ng tagapagpatupad-direktor, kundi pati na rin ang direktor ay magkakaroon ng gawain No. 101.

Una, ang katotohanan tungkol sa relasyon sa pagitan ng direktor at ng gawain sa talahanayan ng empleyado_task ay maiimbak bilang isang string: (4,101).

Pangalawa, ang mga field na minarkahan ng @ManyToMany annotation ay mga proxy object, at kapag na-access ang mga ito, palaging isinasagawa ang isang query sa database.

Kaya't kung magdagdag ka ng isang gawain sa isang empleyado at i-save ang impormasyon tungkol sa empleyado sa database, pagkatapos nito ang gawain ay magkakaroon ng isang bagong tagapagpatupad sa listahan ng mga tagapagpatupad.