3.1 Mapowanie podmiotów zależnych

W SQL możesz pisać zapytania za pomocą JOIN. Czy można zrobić to samo w HQL? Krótka odpowiedź brzmi: tak. Ale pełna odpowiedź będzie bardziej interesująca.

Po pierwsze, kiedy piszemy JOIN w SQL, najczęściej oznacza to, że jedna tabela odnosi się do innej tabeli. Na przykład tabela zadań zawiera kolumnę id_pracownika, która odwołuje się do kolumny id tabeli pracowników.

Tę zależność można opisać za pomocą adnotacji w Hibernate. Najpierw utwórzmy jednostki dla naszych tabel. Najpierw opiszmy tabelę pracowników:

@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;

   @Column(name="name")
   public String name;

   @Column(name="salary")
   public Integer salary;

   @Column(name="join_date")
   public Date joinDate;
}

I klasa EmployeeTask dla tabeli zadań :

@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;

   @Column(name="name")
   public String name;

   @Column(name="employee_id")
   public Integer employeeId;

   @Column(name="deadline")
   public Date deadline;
}

Wszystko jest w porządku, ale jest jedna sugestia. Spójrzmy na pole EmployeeId w ostatnim przykładzie:

@Column(name="employee_id")
public Integer employeeId;

Czy zauważyłeś coś dziwnego? Jeśli nie, oznacza to, że masz już ukształtowany sposób myślenia w języku SQL.

Rzecz w tym, że w języku Java zwykle opisujemy taką zależność trochę inaczej:

public Employee employee;

Nie musimy określać id , zwykle podajemy zmienną, która zawiera odwołanie do obiektu Employee . Lub przechowuje wartość null , jeśli nie ma takiego obiektu.

A Hibernate pozwala nam opisać taką sytuację za pomocą adnotacji:

@ManyToOne
@JoinColumn(name="employee_id", nullable=true)
public Employee employee;

Adnotacja @ManyToOneinformuje Hibernate, że wiele jednostek EmployeeTask może odnosić się do jednej jednostki Employee .

A adnotacja @JoinColumnokreśla nazwę kolumny, z której zostanie pobrany identyfikator . Wszystkie inne niezbędne informacje zostaną pobrane z adnotacji klasy Pracownik.

Ostateczny wynik będzie wyglądał następująco:

@Entity
@Table(name="task")
class EmployeeTask
{
   @Column(name="id")
   public Integer id;

   @Column(name="name")
   public String name;

   @ManyToOne
   @JoinColumn(name="employee_id", nullable=true)
   public Employee employee;

   @Column(name="deadline")
   public Date deadline;
}

3.2 Korzystanie z łączenia w HQL

A teraz przyjrzyjmy się, jak pisać zapytania do powiązanych podmiotów w HQL.

Pierwsza sytuacja.

Mamy pracownika (Employee) i chcemy uzyskać listę jego zadań. Oto jak wyglądałoby to zapytanie w SQL:

SELECT task.* FROM task JOIN employee ON task.employee_id = employee.id
WHERE employee.name = "Ivan Ivanovich";

A teraz napiszmy to samo zapytanie w HQL:

from EmployeeTask where employee.name = "Ivan Ivanovich"

Klasa EmployeeTask ma pole pracownika i pole nazwiska , więc to zapytanie będzie działać.

Sytuacja druga.

Zwróć listę pracowników, którzy mają zaległe zadania. Oto jak wyglądałoby to zapytanie w SQL:

SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();

DISTINCTjest używany, ponieważ do jednego użytkownika można przypisać wiele zadań.

A teraz napiszmy to samo zapytanie w HQL:

select distinct employee from EmployeeTask where deadline < CURDATE();

pracownik w tym zapytaniu jest polem klasy EmployeeTask

Sytuacja trzecia.

Przydziel wszystkie nieprzypisane zadania dyrektorowi. Zapytanie SQL będzie wyglądać następująco:

UPDATE task SET employee_id = 4 WHERE employee_id IS NULL

A teraz napiszmy to samo zapytanie w HQL:

update EmployeeTask set employee = :user where employee is null

Ostatnie zapytanie jest najtrudniejsze. Musimy przekazać identyfikator, dyrektorze, ale klasa EmployeeTask nie zawiera pola, w którym można wpisać id, zamiast tego zawiera pole Pracownik, w którym należy przypisać referencję do obiektu typu Pracownik.

W Hibernate problem ten rozwiązuje się za pomocą parametrów zapytania przekazywanych do obiektu Query. A w samym HQL takie parametry są zapisywane przez dwukropek: :user. Ale porozmawiamy o tym trochę później.