2.1 Kobling på tabellnivå
Vi har sett hvordan Hibernate lagrer samlinger i hjelpetabeller. La oss nå finne ut hvordan du organiserer relasjoner mellom fullverdige tabeller som lagrer ekte Entity-klasser.
Det er fire typer relasjoner mellom Entity-klasser i Hibernate:
- en -til- en
- en -til- mange
- mange -til- en
- mange -til- mange
Og vi vil starte analysen med det enkleste alternativet - mange -til- en .
Du har allerede kommet over et slikt forhold mellom tabeller i SQL. Slik ser det vanligvis 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:
Denne tabellen har følgende kolonner:
- ID INT
- navn VARCHAR
- yrke VARCHAR
- lønn INT
- alder INT
- join_date DATE
Og slik ser oppgavetabellen , som inneholder oppgaver for ansatte, ut:
id | Ansatt 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 bare 4 kolonner:
- id – unikt oppgavenummer (og rader i tabellen);
- ansatt_id – ansatt-ID fra ansatttabellen som oppgaven er tildelt;
- navn – navn og beskrivelse av oppgaven;
- deadline - tidspunktet for når oppgaven skal være fullført.
Vi ser at mange rader i oppgavetabellen kan referere til en enkelt oppføring i ansatttabellen. En slik relasjon på tabellnivå kalles mange-til -en.
2.2 Forholdet til Java-klassenivået
I tillegg til kommunikasjon på tabellnivå, kan du også organisere kommunikasjon på nivå med Entity-klasser i Hibernate. Dette gjøres med en merknad @ManyToOne
.
Men først, la oss bare lage to klasser: Employee og EmployeeTask :
@Entity
@Table(name="employee")
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 en annen klasse for å lagre ansattes jobber:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="employee_id")
public Integer employeeId;
@Column(name="deadline")
public Date deadline;
}
Alt er bra med disse klassene, men det er ingen relasjon mellom dem som vil gjenspeile det faktum at feltet medarbeiderId i klassen EmployeeTask refererer til id-feltet til klassen Employee. Det er på tide å fikse det
2.3 @ManyToOne-kommentar.
For det første, i Java er vi vant til å operere på objekter (og objektreferanser) i stedet for deres id. Så først av alt, i stedet for feltet medarbeiderId i EmployeeTask-klassen, la oss bare peke på et objekt av typen Employee. Slik vil den nye klassen vår se ut:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@ManyToOne
@JoinColumn(name = "employee_id")
public Employee employee;
@Column(name="deadline")
public Date deadline;
}
Ved hjelp av merknaden @ManyToOne
har vi indikert at mange EmployeeTask-objekter kan referere til ett objekt av typen Employee. Ved å bruke merknaden @JoinColumn
, indikerte vi også i hvilken kolonne i tabellen vår ID-en til Employee-objektet er lagret.
2.4 Forespørselseksempler
Og la oss nå vise noen eksempler på hvordan Hibernate kan fungere med slike relaterte klasser.
Scenario en
La oss skrive en spørring for å finne ut alle oppgavene som er tildelt en bestemt bruker. Slik vil denne spørringen se ut i HQL:
from EmployeeTask where employee.name = "Ivan Ivanovich"
Du kan ganske enkelt referere til felt med avhengige klasser gjennom en prikk. Det er veldig behagelig. Men la oss fortsatt skrive denne spørringen i form av Java-kode:
String hql = "from EmployeeTask where employee.name = :username";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter("username", "Ivan Ivanovich");
List<EmployeeTask> resultLIst = query.list();
Scenario to
La oss skrive en spørring som returnerer en liste over ansatte som har forfalte oppgaver. En oppgave er forsinket hvis fristen er i fortiden. Slik vil spørringen se ut i SQL:
SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();
DISTINCT
brukes fordi det kan være mange oppgaver tildelt én bruker.
Og la oss nå skrive den samme spørringen i HQL:
select distinct employee from EmployeeTask where deadline < CURDATE();
Ansatt i denne spørringen er et felt i EmployeeTask-klassen
Situasjon tre
Tildel alle ikke-tildelte oppgaver til direktøren. SQL-spørringen vil se slik ut:
UPDATE task SET employee_id = 4 WHERE employee_id IS NULL
Og la oss nå skrive den samme spørringen i HQL:
update EmployeeTask set employee = :user where employee is null
Det siste søket er det vanskeligste. Vi må sende ID-en til direktøren, men EmployeeTask-klassen inneholder ikke et felt der vi kan skrive en id, i stedet inneholder den et Employee-felt der vi må tilordne en referanse til et objekt av typen Employee.
Employee director = session.get(Employee.class, 4);
String hql = "update EmployeeTask set employee = :user where employee is null";
Query<EmployeeTask> query = session.createQuery(hql, EmployeeTask.class);
query.setParameter("user", director);
query.executeUpdate();