2.1 Koppelen op tafelniveau
We hebben gezien hoe Hibernate collecties opslaat in hulptabellen. Laten we nu eens kijken hoe we relaties kunnen organiseren tussen volwaardige tabellen waarin echte Entity-klassen zijn opgeslagen.
Er zijn vier soorten relaties tussen Entity-klassen in Hibernate:
- een -op- een
- een -op- veel
- veel -op- een
- veel -op- veel
En we beginnen de analyse met de eenvoudigste optie - veel -op- een .
Zo'n relatie tussen tabellen ben je al eens tegengekomen in SQL. Zo ziet het er meestal uit:
ID kaart | naam | bezigheid | salaris | leeftijd | join_date |
---|---|---|---|---|---|
1 | Ivanov Ivan | Programmeur | 100000 | 25 | 2012-06-30 |
2 | Petrov Petr | Programmeur | 80000 | 23 | 2013-08-12 |
3 | Ivanov Sergej | Tester | 40000 | dertig | 01-01-2014 |
4 | Rabinovich Moisha | Regisseur | 200000 | 35 | 2015-05-12 |
5 | Kirienko Anastasia | Officemanager | 40000 | 25 | 2015-10-10 |
6 | Vaska | Kat | 1000 | 3 | 2018-11-11 |
werknemers tafel:
Deze tabel heeft de volgende kolommen:
- id INT
- naam VARCHAR
- bezetting VARCHAR
- salaris INT
- leeftijd INT
- join_date DATUM
En zo ziet de takentabel , die taken voor medewerkers bevat, er uit:
ID kaart | medewerker_id | naam | deadline |
---|---|---|---|
1 | 1 | Los een bug op de frontend op | 01-06-2022 |
2 | 2 | Los een bug op de backend op | 2022-06-15 |
3 | 5 | Koop koffie | 01-07-2022 |
4 | 5 | Koop koffie | 01-08-2022 |
5 | 5 | Koop koffie | 01-09-2022 |
6 | (NUL) | Ruim het kantoor op | (NUL) |
7 | 4 | Geniet van het leven | (NUL) |
8 | 6 | Geniet van het leven | (NUL) |
Deze tabel heeft slechts 4 kolommen:
- id – uniek taaknummer (en rijen in de tabel);
- employee_id – werknemer-ID van de werknemerstabel waaraan de taak is toegewezen;
- naam – naam en omschrijving van de taak;
- deadline - de tijd waarop de taak moet zijn voltooid.
We zien dat veel rijen in de takentabel kunnen verwijzen naar een enkel item in de werknemerstabel. Zo'n relatie op tabelniveau wordt veel-op -een genoemd.
2.2 Relatie met het Java-klasseniveau
Naast communicatie op tafelniveau kun je in Hibernate ook communicatie organiseren op het niveau van Entity-klassen. Dit gebeurt met een annotatie @ManyToOne
.
Maar laten we eerst twee klassen maken: Employee en 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;
}
En een tweede klasse om banen van werknemers op te slaan:
@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;
}
Alles is goed met deze klassen, maar er is geen relatie tussen hen die zou weerspiegelen dat het veld employeeId van de klasse EmployeeTask verwijst naar het veld id van de klasse Employee. Het is tijd om het te repareren
2.3 @ManyToOne-annotatie.
Ten eerste zijn we in Java gewend om op objecten (en objectreferenties) te werken in plaats van op hun id. Laten we dus allereerst in plaats van het veld employeeId in de klasse EmployeeTask, een object van het type Employee aanwijzen. Zo ziet onze nieuwe klas eruit:
@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;
}
Met behulp van de annotatie @ManyToOne
hebben we aangegeven dat veel EmployeeTask-objecten kunnen verwijzen naar één object van het type Employee. Ook hebben we met behulp van de annotatie aangegeven in welke kolom van onze tabel de id van het Employee-object is opgeslagen. @JoinColumn
2.4 Vraag voorbeelden aan
En laten we nu enkele voorbeelden laten zien van hoe Hibernate met dergelijke verwante klassen kan werken.
Scenario één
Laten we een query schrijven om alle taken te achterhalen die aan een specifieke gebruiker zijn toegewezen. Hier is hoe deze query eruit zou zien in HQL:
from EmployeeTask where employee.name = "Ivan Ivanovich"
U kunt eenvoudig verwijzen naar velden van afhankelijke klassen door middel van een punt. Het is zeer comfortabel. Maar laten we deze query nog steeds schrijven in de vorm van Java-code:
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 twee
Laten we een query schrijven die een lijst retourneert van werknemers die achterstallige taken hebben. Een taak is achterstallig als de deadline in het verleden ligt. Dit is hoe die query eruit zou zien in SQL:
SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();
DISTINCT
wordt gebruikt omdat er veel taken aan één gebruiker kunnen worden toegewezen.
En laten we nu dezelfde query in HQL schrijven:
select distinct employee from EmployeeTask where deadline < CURDATE();
Werknemer in deze query is een veld van de klasse EmployeeTask
Situatie drie
Wijs alle niet-toegewezen taken toe aan de directeur. De SQL-query ziet er als volgt uit:
UPDATE task SET employee_id = 4 WHERE employee_id IS NULL
En laten we nu dezelfde query in HQL schrijven:
update EmployeeTask set employee = :user where employee is null
De laatste vraag is de moeilijkste. We moeten de ID van de directeur doorgeven, maar de klasse EmployeeTask bevat geen veld waarin we een id kunnen schrijven, maar bevat een veld Employee waarin we een verwijzing moeten toewijzen aan een object van het type 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();
GO TO FULL VERSION