5.1 Różne formy komunikacji jeden-do-jednego

Jest jeszcze jeden ciekawy i dość specyficzny przypadek relacji pomiędzy dwiema klasami Entity - relacja jeden-do-jednego.

Nazywam ten przypadek bardzo specyficznym, ponieważ dotyczy bardziej obiektów Java niż bazy danych. W bazie danych istnieją tylko dwie opcje relacji między tabelami:

  • Wiersz tabeli zawiera łącze do identyfikatora innej tabeli.
  • Tabela usług jest używana w relacjach wiele-do-wielu.

W przypadku klas Entity mogą istnieć opcje opisane kilkoma adnotacjami:

  • @Osadzony
  • Jednostronny OneToOne
  • Dwustronne OneToOne
  • @MapsId

Poniżej rozważymy najpopularniejsze z nich.

5.2 Osadzony

Nawiasem mówiąc, rozważaliśmy już najprostszą opcję komunikacji jeden do jednego@Embedded - to jest adnotacja . W tym przypadku mamy dwie klasy przechowywane w tej samej tabeli w bazie danych.

Powiedzmy, że chcemy przechowywać adres użytkownika w klasie 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;
}

Następnie musimy tylko dodać pole z tym adresem do klasy User :


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

Resztą zajmie się Hibernate: dane będą przechowywane w jednej tabeli, ale podczas pisania zapytań HQL będziesz musiał operować na polach klas.

Przykład zapytania HQL:

select from User where address.city = 'Paris'

5.3 Jednostronny OneToOne

Wyobraźmy sobie teraz sytuację: mamy tabelę źródłową pracownik i zadanie, które odnosi się do pracownika. Ale wiemy na pewno, że jednemu użytkownikowi można przypisać maksymalnie jedno zadanie. Następnie możemy użyć adnotacji do opisania tej sytuacji @OneToOne.

Przykład:


@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 zadba o to, aby nie tylko jedno zadanie miało jednego użytkownika, ale także, aby jeden użytkownik miał tylko jedno zadanie. W przeciwnym razie ten przypadek praktycznie nie różni się od @ManyToOne.

5.4 Dwustronne umowy jeden na jeden

Poprzednia opcja może być trochę niewygodna, ponieważ często chcesz przypisać pracownika nie tylko do zadania, ale również przypisać zadanie pracownikowi.

W tym celu możesz dodać pole EmployeeTask do klasy Pracownik i nadać mu odpowiednie adnotacje.


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

Ważny!Tabela pracowników nie zawiera pola id_zadania , zamiast tego pole id_pracownika w tabeli zadań służy do ustalania relacji między tabelami .

Nawiązanie połączenia między obiektami wygląda następująco:


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

Aby usunąć łącze, należy również usunąć łącza z obu obiektów:


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