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 @ManyToOne
informuje Hibernate, że wiele jednostek EmployeeTask może odnosić się do jednej jednostki Employee .
A adnotacja @JoinColumn
okreś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();
DISTINCT
jest 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.
GO TO FULL VERSION