Szervizasztal
Most nézzünk egy másik gyakori esetet – sok-sok. Képzeljük el, hogy sok-sok kapcsolat van a feladatok és az alkalmazottak között :
- Az alkalmazotti táblában egy alkalmazott sok feladatot elvégezhet a feladattáblából.
- A feladattáblázatban egy feladat több alkalmazotthoz is hozzárendelhető.
Ezt az entitások közötti kapcsolatot sok-sok-hoz hívják. És ahhoz, hogy SQL szinten megvalósítsuk, szükségünk van egy további szolgáltatási táblára. Nevezzük például alkalmazott_feladatnak.
A munkavállaló_feladat tábla csak két oszlopot tartalmaz:
- munkavállalói azonosító
- feladat_azonosítója
Minden alkalommal, amikor egy adott feladatot rendelünk egy adott felhasználóhoz, egy új sor kerül hozzáadásra ehhez a táblázathoz. Példa:
munkavállalói azonosító | feladat_azonosítója |
---|---|
1 | 1 |
1 | 2 |
2 | 3 |
Nos, a feladattáblának el kell veszítenie az alkalmazott_azonosító oszlopát . Ennek csak akkor van értelme, ha a feladatot csak egy alkalmazotthoz lehet hozzárendelni. Ha a feladat több alkalmazotthoz is hozzárendelhető, akkor ezeket az információkat a munkavállaló_feladat szolgáltatástáblában kell tárolni .
Táblázat szintű kapcsolat
Így fognak kinézni új asztalaink:
id | név | Foglalkozása | fizetés | kor | csatlakozás dátuma |
---|---|---|---|---|---|
1 | Ivanov Iván | Programozó | 100 000 | 25 | 2012-06-30 |
2 | Petrov Petr | Programozó | 80000 | 23 | 2013-08-12 |
3 | Ivanov Szergej | Vizsgáló | 40000 | harminc | 2014-01-01 |
4 | Rabinovics Moisa | Rendező | 200 000 | 35 | 2015-05-12 |
5 | Kirienko Anasztázia | Irodavezető | 40000 | 25 | 2015-10-10 |
6 | Vaska | Macska | 1000 | 3 | 2018-11-11 |
Alkalmazottak táblázata ( nem változott ) :
Ez a táblázat a következő oszlopokat tartalmazza:
- azonosító INT
- név VARCHAR
- foglalkozás VARCHAR
- fizetés INT
- kor INT
- csatlakozási_dátum DATE
És így néz ki a feladattábla , elvesztette a munkavállaló_id oszlopát (pirossal jelölve):
id | employee_id | név | határidő |
---|---|---|---|
1 | 1 | Javítson ki egy hibát a kezelőfelületen | 2022-06-01 |
2 | 2 | Javítson ki egy hibát a háttérben | 2022-06-15 |
3 | 5 | Vegyél kávét | 2022-07-01 |
4 | 5 | Vegyél kávét | 2022-08-01 |
5 | 5 | Vegyél kávét | 2022-09-01 |
6 | (NULLA) | Takarítsd ki az irodát | (NULLA) |
7 | 4 | Élvezd az életet | (NULLA) |
8 | 6 | Élvezd az életet | (NULLA) |
Ez a táblázat már csak 3 oszlopot tartalmaz:
- id - egyedi feladatszám (és sorok a táblázatban)
- munkavállalói_azonosító – (eltávolítva)
- név - a feladat neve és leírása
- határidő - az az idő, ameddig a feladatot el kell végezni
Rendelkezünk a munkavállalói_feladat szolgáltatási táblával is , ahol a munkavállalói_id adatok áttelepültek a feladattáblából:
munkavállalói azonosító | feladat_azonosítója |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
(NULLA) | 6 |
4 | 7 |
6 | 8 |
Szándékosan mentettem el ideiglenesen a törölt oszlopot a feladattáblába, így láthatja, hogy az abból származó adatok átkerültek az alkalmazott_feladat táblába.
Egy másik fontos pont a "(NULL) 6" piros vonal a munkavállaló_feladat táblában. Pirossal jelöltem, mert nem lesz benne az alkalmazott_feladat táblában .
Ha a 7. feladat a 4. felhasználóhoz van hozzárendelve, akkor a munkavállaló_feladat táblában legyen egy sor (4, 7).
Ha a 6. feladat nincs hozzárendelve senkihez, akkor egyszerűen nem lesz róla rekord a munkavállaló_feladat táblában. Így fognak kinézni a táblázatok végleges verziói:
feladat táblázat :
id | név | határidő |
---|---|---|
1 | Javítson ki egy hibát a kezelőfelületen | 2022-06-01 |
2 | Javítson ki egy hibát a háttérben | 2022-06-15 |
3 | Vegyél kávét | 2022-07-01 |
4 | Vegyél kávét | 2022-08-01 |
5 | Vegyél kávét | 2022-09-01 |
6 | Takarítsd ki az irodát | (NULLA) |
7 | Élvezd az életet | (NULLA) |
8 | Élvezd az életet | (NULLA) |
munkavállaló_feladat táblázat:
munkavállalói azonosító | feladat_azonosítója |
---|---|
1 | 1 |
2 | 2 |
5 | 3 |
5 | 4 |
5 | 5 |
4 | 7 |
6 | 8 |
Kommunikáció Java osztályszinten
De az Entity-osztályok szintű kommunikációval teljes a rendünk. Kezdjük a jó hírrel.
Először is, a Hibernate egy speciális @ManyToMany megjegyzéssel rendelkezik , amely lehetővé teszi a sok a sokhoz tábla kapcsolat esetének megfelelő leírását.
Másodszor, két Entity osztály még mindig elég nekünk. A szervizasztalhoz nincs szükségünk osztályra.
Így fognak kinézni az óráink. Az Employee osztály eredeti formájában:
@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;
}
És az EmployeeTask osztály eredeti formájában:
@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 kommentár
A példákban a meglévő mezőket kihagyom, de újakat adok hozzá. Így fognak kinézni. Alkalmazotti osztály :
@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>();
}
És az EmployeeTask osztály :
@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>();
}
Úgy tűnik, hogy minden bonyolult, de valójában minden egyszerű.
Először is a @JoinTable annotációt használja (nem tévesztendő össze a @JoinColumn-nel), amely leírja a munkavállalói_feladat szolgáltatási táblát.
Másodszor, leírja, hogy a munkavállaló_feladat tábla task_id oszlopa a feladattábla id oszlopára hivatkozik.
Harmadszor azt mondja, hogy a munkavállaló_feladat tábla munkavállalói_azonosító oszlopa az alkalmazotti tábla id oszlopára vonatkozik.
Tulajdonképpen annotációk segítségével leírtuk, hogy a munkavállaló_feladat tábla milyen adatokat tartalmaz, és a Hibernate hogyan értelmezze azokat.
De most nagyon könnyen hozzáadhatunk (és törölhetünk) egy feladatot bármelyik alkalmazotthoz. És bármilyen előadót hozzáadhat bármilyen feladathoz.
Kérjen példákat
Írjunk néhány érdekes kérdést, hogy jobban megértsük, hogyan működnek ezek a ManyToMany mezők. És pontosan az elvárásoknak megfelelően működnek.
Először is, a régi kódunk változtatás nélkül fog működni, mivel a rendezőnek korábban volt feladatmezője:
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();
Másodszor, ha egy feladathoz egy másik előadót akarunk hozzárendelni, akkor ezt még egyszerűbb megtenni:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);
session.update(task);
session.flush();
Fontos! Ezen felkérés teljesítése következtében nemcsak a feladatnak lesz végrehajtó-irányítója, hanem az igazgatónak is lesz 101. számú feladata.
Először is, az igazgató és a feladat közötti kapcsolat ténye az alkalmazott_feladat táblában karakterláncként kerül tárolásra: (4,101).
Másodszor, a @ManyToMany megjegyzésekkel jelölt mezők proxy objektumok, és amikor elérjük őket, akkor mindig adatbázis-lekérdezés kerül végrehajtásra.
Tehát ha felvesz egy feladatot egy alkalmazotthoz és elmenti az adatbázisba az alkalmazott adatait, akkor ezután a feladatnak új végrehajtója lesz a végrehajtók listájában.