5.1 Diverse forme de comunicare unu-la-unu
Există un alt caz interesant și destul de specific al unei relații între două clase de Entități - o relație unu-la-unu.
Eu numesc acest caz foarte specific, deoarece este mai mult despre obiecte Java decât despre o bază de date. În baza de date, există doar două opțiuni pentru relația dintre tabele:
- Rândul tabelului conține un link către id-ul altui tabel.
- Tabelul de servicii este folosit pentru relații multi-la-multe.
În cazul claselor de Entități, pot exista opțiuni care sunt descrise prin mai multe adnotări:
- @Încorporat
- OneToOne unilateral
- OneToOne bilateral
- @MapsId
Mai jos le vom considera pe cele mai populare dintre ele.
5.2 Încorporat
Apropo, am luat deja în considerare cea mai simplă opțiune de comunicare unu-la-unu@Embedded
- aceasta este o adnotare . În acest caz, avem două clase stocate în același tabel în baza de date.
Să presupunem că vrem să stocăm adresa utilizatorului în clasa UserAddress :
@Embeddable
class UserAddress {
@Column(name="user_address_country")
public String country;
@Column(name="user_address_city")
public String city;
@Column(name="user_address_street")
public String street;
@Column(name="user_address_home")
public String home;
}
Apoi trebuie doar să adăugăm un câmp cu această adresă la clasa User :
@Entity
@Table(name="user")
class User {
@Column(name="id")
public Integer id;
@Embedded
public UserAddress address;
@Column(name="created_date")
public Date createdDate;
}
Hibernate va face restul: datele vor fi stocate într-un singur tabel, dar când scrieți interogări HQL, va trebui să operați pe câmpuri de clasă.
Exemplu de interogare HQL:
select from User where address.city = 'Paris'
5.3 OneToOne unilateral
Imaginați-vă acum situația: avem un angajat de tabel sursă și o sarcină care se referă la angajat. Dar știm cu siguranță că unui utilizator poate fi atribuită maxim o sarcină. Apoi putem folosi adnotarea pentru a descrie această situație @OneToOne
.
Exemplu:
@Entity
@Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@OneToOne
@JoinColumn(name = "employee_id")
public Employee employee;
@Column(name="deadline")
public Date deadline;
}
Hibernare se va asigura că nu numai o sarcină are un utilizator, ci și că un utilizator are o singură sarcină. În caz contrar, acest caz nu este practic diferit de @ManyToOne
.
5.4 OneToOne bilateral
Opțiunea anterioară poate fi puțin incomodă, deoarece adesea doriți să atribuiți un angajat nu numai unei sarcini, ci și să atribuiți o sarcină unui angajat.
Pentru a face acest lucru, puteți adăuga câmpul EmployeeTask la clasa Employee și îi puteți da adnotările corecte.
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
private EmployeeTask task;
}
Important!Tabelul angajat nu are un câmp task_id , în schimb câmpul employee_id al tabelului task este folosit pentru a stabili o relație între tabele .
Stabilirea unei conexiuni între obiecte arată astfel:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employee = director;
director.task = task;
session.update(task);
session.flush();
Pentru a elimina legătura, legăturile trebuie, de asemenea, eliminate din ambele obiecte:
Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.task;
task.employee = null;
session.update(task);
director.task = null;
session.update(director);
session.flush();