2.1 Collegamento a livello di tabella
Abbiamo visto come Hibernate memorizza le raccolte in tabelle ausiliarie. Ora scopriamo come organizzare le relazioni tra tabelle a tutti gli effetti che memorizzano le classi Entity reali.
Esistono quattro tipi di relazioni tra le classi Entity in Hibernate:
- uno a uno
- uno a molti
- molti -a- uno
- molti - a - molti
E inizieremo l'analisi con l'opzione più semplice: molti a uno .
Hai già riscontrato una tale relazione tra le tabelle in SQL. Ecco come appare di solito:
id | nome | occupazione | stipendio | età | data di iscrizione |
---|---|---|---|---|---|
1 | Ivanov Ivan | Programmatore | 100000 | 25 | 2012-06-30 |
2 | Petrov Petr | Programmatore | 80000 | 23 | 2013-08-12 |
3 | Sergej Ivanov | Tester | 40000 | trenta | 2014-01-01 |
4 | Rabinovich Moisha | Direttore | 200000 | 35 | 2015-05-12 |
5 | Kirienko Anastasia | Capo ufficio | 40000 | 25 | 2015-10-10 |
6 | Vasca | Gatto | 1000 | 3 | 2018-11-11 |
tabella dei dipendenti:
Questa tabella ha le seguenti colonne:
- id INT
- nome VARCHAR
- occupazione VARCHAR
- stipendio INT
- età INT
- join_date DATE
Ed ecco come appare la tabella delle attività , che contiene le attività per i dipendenti:
id | ID Dipendente | nome | scadenza |
---|---|---|---|
1 | 1 | Risolto un bug sul frontend | 2022-06-01 |
2 | 2 | Risolto un bug sul backend | 2022-06-15 |
3 | 5 | Compra il caffè | 2022-07-01 |
4 | 5 | Compra il caffè | 2022-08-01 |
5 | 5 | Compra il caffè | 2022-09-01 |
6 | (NULLO) | Pulisci l'ufficio | (NULLO) |
7 | 4 | Goditi la vita | (NULLO) |
8 | 6 | Goditi la vita | (NULLO) |
Questa tabella ha solo 4 colonne:
- id – numero univoco dell'attività (e righe nella tabella);
- employee_id – ID dipendente dalla tabella dei dipendenti a cui è assegnata l'attività;
- name – nome e descrizione dell'attività;
- scadenza - il tempo entro il quale l'attività deve essere completata.
Vediamo che molte righe nella tabella delle attività possono fare riferimento a una singola voce nella tabella dei dipendenti. Tale relazione a livello di tabella è chiamata molti-a -uno.
2.2 Relazione con il livello di classe Java
Oltre alla comunicazione a livello di tabella, puoi anche organizzare la comunicazione a livello di classi di entità in Hibernate. Questo viene fatto con un'annotazione @ManyToOne
.
Ma prima, creiamo solo due classi: Employee e 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;
}
E una seconda classe per archiviare i lavori dei dipendenti:
@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;
}
Tutto va bene con queste classi, ma non c'è alcuna relazione tra loro che rifletta il fatto che il campo employeeId della classe EmployeeTask fa riferimento al campo id della classe Employee. È ora di aggiustarlo
2.3 Annotazione @ManyToOne.
Innanzitutto, in Java siamo abituati a operare su oggetti (e riferimenti a oggetti) piuttosto che sul loro id. Quindi prima di tutto, invece del campo employeeId nella classe EmployeeTask, puntiamo semplicemente a un oggetto di tipo Employee. Ecco come sarà la nostra nuova classe:
@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;
}
Con l'aiuto dell'annotazione @ManyToOne
, abbiamo indicato che molti oggetti EmployeeTask possono fare riferimento a un oggetto di tipo Employee. Inoltre, utilizzando l'annotazione @JoinColumn
, abbiamo indicato in quale colonna della nostra tabella è memorizzato l'id dell'oggetto Employee.
2.4 Richiedi esempi
E ora mostriamo alcuni esempi di come Hibernate può lavorare con tali classi correlate.
Scenario uno
Scriviamo una query per scoprire tutte le attività che sono state assegnate a un utente specifico. Ecco come apparirebbe questa query in HQL:
from EmployeeTask where employee.name = "Ivan Ivanovich"
Puoi semplicemente fare riferimento ai campi delle classi dipendenti attraverso un punto. È molto comodo. Ma scriviamo ancora questa query sotto forma di codice Java:
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 due
Scriviamo una query che restituisca un elenco di dipendenti con attività scadute. Un'attività è scaduta se la sua scadenza è nel passato. Ecco come sarebbe quella query in SQL:
SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();
DISTINCT
viene utilizzato perché possono essere assegnate molte attività a un utente.
E ora scriviamo la stessa query in HQL:
select distinct employee from EmployeeTask where deadline < CURDATE();
Il dipendente in questa query è un campo della classe EmployeeTask
Situazione tre
Assegna tutte le attività non assegnate al direttore. La query SQL sarà simile a questa:
UPDATE task SET employee_id = 4 WHERE employee_id IS NULL
E ora scriviamo la stessa query in HQL:
update EmployeeTask set employee = :user where employee is null
L'ultima domanda è la più difficile. Dobbiamo passare l'ID del direttore, ma la classe EmployeeTask non contiene un campo in cui possiamo scrivere un id, invece contiene un campo Employee in cui dobbiamo assegnare un riferimento a un oggetto di tipo 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