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

DISTINCTbrukes 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();