5.1 Различни форми на комуникация един към един

Има още един интересен и доста специфичен случай на връзка между два класа Entity - връзка едно към едно.

Наричам този случай много специфичен, тъй като става въпрос повече за Java обекти, отколкото за база данни. В базата данни има само две опции за връзката между таблиците:

  • Редът на tableта съдържа връзка към идентификатора на друга table.
  • Сервизната table се използва за релации много към много.

В случай на класове Entity може да има опции, които са описани с няколко анотации:

  • @Вграден
  • Едностранно OneToOne
  • Двустранен OneToOne
  • @MapsId

По-долу ще разгледаме най-популярните от тях.

5.2 Вграден

Между другото, вече разгледахме най -простата опция за комуникация един към един@Embedded - това е анотация . В този случай имаме два класа, съхранени в една и съща table в базата данни.

Да кажем, че искаме да съхраним address на потребителя в класа 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;
}

След това просто трябва да добавим поле с този address към потребителския клас :


@Entity
@Table(name="user")
class User {
   @Column(name="id")
   public Integer id;
 
   @Embedded
   public UserAddress address;
 
   @Column(name="created_date")
   public Date createdDate;
}

Hibernate ще свърши останалото: данните ще се съхраняват в една table, но когато пишете HQL заявки, ще трябва да работите с полета на класа.

Пример за HQL заявка:

select from User where address.city = 'Paris'

5.3 Едностранно един към един

Представете си сега ситуацията: имаме изходна table employee и задача, която се отнася до служител. Но знаем със сигурност, че на един потребител може да бъде възложена максимум една задача. Тогава можем да използваме анотацията, за да опишем тази ситуация @OneToOne.

Пример:


@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;
}

Hibernate ще гарантира, че не само една задача има един потребител, но и че един потребител има само една задача. В противен случай този случай практически не се различава от @ManyToOne.

5.4 Двустранно един към един

Предишната опция може да бъде малко неудобна, защото често искате да възложите служител не само на задача, но и да възложите задача на служител.

За да направите това, можете да добавите полето EmployeeTask към класа Employee и да му дадете правилните анотации.


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
   private EmployeeTask task;
}

важно!Таблицата на служителите няма поле task_id , instead of това полето employee_id на tableта със задачи се използва за установяване на връзка между таблиците .

Установяването на връзка между обекти изглежда така:


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

За да премахнете връзката, връзките трябва да бъдат премахнати и от двата обекта:


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