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