3.1 Картографиране на зависими обекти

В SQL можете да пишете заявки с помощта на JOIN. Възможно ли е да се направи същото в HQL? Краткият отговор е да. Но пълният отговор ще бъде по-интересен.

Първо, когато пишем JOIN в SQL, това най-често означава, че една table препраща към друга table. Например tableта на задачите съдържа колона employee_id, която препраща към колоната id на tableта на служителите.

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

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

И класът EmployeeTask за tableта със задачи :

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

Всичко е наред, но има едно предложение. Нека да разгледаме полето employeeId в последния пример:

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

Забелязвате ли нещо странно? Ако не, това означава, че вече сте формирали начин на мислене на езика SQL.

Работата е там, че в езика Java ние обикновено описваме такава зависимост малко по-различно:

public Employee employee;

Не е необходимо да посочваме id , обикновено просто посочваме променлива, която съдържа препратка към обекта Employee . Или съхранява null, ако няма такъв обект.

И Hibernate ни позволява да опишем такава ситуация с помощта на анотации:

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

Анотацията @ManyToOneказва на Hibernate, че много обекти EmployeeTask могат да препращат към един обект Employee .

А анотацията @JoinColumnуказва името на колоната, от която ще бъде взет идентификаторът . Цялата друга необходима информация ще бъде взета от анотациите на класа Employee.

Крайният резултат ще изглежда така:

@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 Използване на join в HQL

А сега нека да разгледаме How да пишете заявки към свързани обекти в HQL.

Първа ситуация.

Имаме служител (Employee) и искаме да получим списък с неговите задачи. Ето How ще изглежда тази заявка в SQL:

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

А сега нека напишем същата заявка в HQL:

from EmployeeTask where employee.name = "Ivan Ivanovich"

Класът EmployeeTask има поле за служител и поле за име , така че тази заявка ще работи.

Ситуация две.

Върнете списък със служители, които имат просрочени задачи. Ето How ще изглежда тази заявка в SQL:

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

DISTINCTсе използва, защото може да има много задачи, възложени на един потребител.

А сега нека напишем същата заявка в HQL:

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

служител в тази заявка е поле от класа EmployeeTask

Ситуация трета.

Възложете всички невъзложени задачи на директора. SQL заявката ще изглежда така:

UPDATE task SET employee_id = 4 WHERE employee_id IS NULL

А сега нека напишем същата заявка в HQL:

update EmployeeTask set employee = :user where employee is null

Последното запитване е най-трудното. Трябва да предадем ID, директор, но класът EmployeeTask не съдържа поле, където можете да напишете идентификатор, instead of това съдържа поле Employee, където трябва да присвоите препратка към обект от тип Employee.

В Hibernate този проблем се решава с помощта на параметри на заявката, които се предават на обекта Query. И в самия HQL такива параметри се записват чрез двоеточие: :user. Но ще говорим за това малко по-късно.