2.1 Länkning på tabellnivå
Vi har sett hur Hibernate lagrar samlingar i hjälpbord. Låt oss nu ta reda på hur man organiserar relationer mellan fullfjädrade tabeller som lagrar riktiga Entity-klasser.
Det finns fyra typer av relationer mellan Entity-klasser i Hibernate:
- en till en
- en till många
- många till en
- många -till- många
Och vi kommer att börja analysen med det enklaste alternativet - många -till- en .
Du har redan stött på ett sådant förhållande mellan tabeller i SQL. Så här ser det vanligtvis ut:
id | namn | ockupation | lön | ålder | join_date |
---|---|---|---|---|---|
1 | Ivanov Ivan | Programmerare | 100 000 | 25 | 2012-06-30 |
2 | Petrov Petr | Programmerare | 80 000 | 23 | 2013-08-12 |
3 | Ivanov Sergey | Testare | 40 000 | trettio | 2014-01-01 |
4 | Rabinovich Moisha | Direktör | 200 000 | 35 | 2015-05-12 |
5 | Kirienko Anastasia | Kontors chef | 40 000 | 25 | 2015-10-10 |
6 | Vaska | Katt | 1000 | 3 | 2018-11-11 |
anställd tabell:
Den här tabellen har följande kolumner:
- id INT
- namn VARCHAR
- yrke VARCHAR
- lön INT
- ålder INT
- join_date DATE
Och så här ser uppgiftstabellen ut, som innehåller uppgifter för anställda:
id | Anställnings-ID | namn | deadline |
---|---|---|---|
1 | 1 | Fixa en bugg på frontend | 2022-06-01 |
2 | 2 | Fixa en bugg på backend | 2022-06-15 |
3 | 5 | Köp kaffe | 2022-07-01 |
4 | 5 | Köp kaffe | 2022-08-01 |
5 | 5 | Köp kaffe | 2022-09-01 |
6 | (NULL) | Städa kontoret | (NULL) |
7 | 4 | Njut av livet | (NULL) |
8 | 6 | Njut av livet | (NULL) |
Den här tabellen har bara 4 kolumner:
- id – unikt uppgiftsnummer (och rader i tabellen);
- anställd_id – anställd-ID från den anställda tabellen som uppgiften är tilldelad;
- namn – namn och beskrivning av uppgiften;
- deadline - den tidpunkt då uppgiften ska vara klar.
Vi ser att många rader i uppgiftstabellen kan hänvisa till en enda post i medarbetartabellen. En sådan relation på tabellnivå kallas många-till- en.
2.2 Relation till Java-klassnivån
Förutom kommunikation på tabellnivå kan du också organisera kommunikation på nivå med Entity-klasser i Hibernate. Detta görs med en anteckning @ManyToOne
.
Men först, låt oss bara skapa två klasser: Employee och 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;
}
Och en andra klass för att lagra anställdas jobb:
@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;
}
Allt är bra med dessa klasser, men det finns inget samband mellan dem som skulle återspegla det faktum att fältet EmployeeTask hänvisar till id-fältet i klassen Employee. Det är dags att fixa det
2.3 @ManyToOne-anteckning.
För det första är vi i Java vana vid att arbeta på objekt (och objektreferenser) snarare än deras id. Så först och främst, istället för fältet employeeId i klassen EmployeeTask, låt oss bara peka på ett objekt av typen Employee. Så här kommer vår nya klass att 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;
}
Med hjälp av anteckningen @ManyToOne
har vi angett att många EmployeeTask-objekt kan referera till ett objekt av typen Employee. Med hjälp av anteckningen angav vi också @JoinColumn
i vilken kolumn i vår tabell ID för Employee-objektet lagras.
2.4 Exempel på begäran
Och låt oss nu visa några exempel på hur Hibernate kan fungera med sådana relaterade klasser.
Scenario ett
Låt oss skriva en fråga för att ta reda på alla uppgifter som har tilldelats en specifik användare. Så här skulle den här frågan se ut i HQL:
from EmployeeTask where employee.name = "Ivan Ivanovich"
Du kan helt enkelt referera till fält med beroende klasser genom en punkt. Det är väldigt bekvämt. Men låt oss ändå skriva den här frågan i form av Java-kod:
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 två
Låt oss skriva en fråga som returnerar en lista över anställda som har försenade uppgifter. En uppgift är försenad om dess deadline ligger i det förflutna. Så här skulle den frågan se ut i SQL:
SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();
DISTINCT
används eftersom det kan vara många uppgifter tilldelade en användare.
Och låt oss nu skriva samma fråga i HQL:
select distinct employee from EmployeeTask where deadline < CURDATE();
Anställd i den här frågan är ett fält i klassen EmployeeTask
Situation tre
Tilldela alla otilldelade uppgifter till regissören. SQL-frågan kommer att se ut så här:
UPDATE task SET employee_id = 4 WHERE employee_id IS NULL
Och låt oss nu skriva samma fråga i HQL:
update EmployeeTask set employee = :user where employee is null
Den sista frågan är den svåraste. Vi måste skicka med ID för direktören, men EmployeeTask-klassen innehåller inte ett fält där vi kan skriva ett id, istället innehåller det ett Employee-fält där vi behöver tilldela en referens till ett 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();