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

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