3.1 Mapeo de entidades dependientes

En SQL, puede escribir consultas usando JOIN. ¿Es posible hacer lo mismo en HQL? La respuesta corta es sí. Pero la respuesta completa será más interesante.

Primero, cuando escribimos un JOIN en SQL, generalmente significa que una tabla se refiere a otra tabla. Por ejemplo, la tabla de tareas contiene una columna employee_id que hace referencia a la columna id de la tabla de empleados.

Esta dependencia se puede describir usando anotaciones en Hibernate. Primero, creemos Entidades para nuestras tablas. Primero, describamos la tabla de empleados:

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

Y la clase EmployeeTask para la tabla de tareas :

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

Todo está bien, pero hay una sugerencia. Veamos el campo employeeId en el último ejemplo:

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

¿Notas algo extraño? Si no, significa que ya ha formado una forma de pensar en el lenguaje SQL.

La cuestión es que en el lenguaje Java, normalmente describimos esa dependencia de forma un poco diferente:

public Employee employee;

No necesitamos especificar una identificación , generalmente solo especificamos una variable que contiene una referencia al objeto Empleado . O almacena nulo si no existe tal objeto.

E Hibernate nos permite describir tal situación usando anotaciones:

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

La anotación @ManyToOnele dice a Hibernate que muchas entidades EmployeeTask pueden referirse a una entidad Employee .

Y la anotación @JoinColumnespecifica el nombre de la columna de la que se tomará la identificación . Toda la demás información necesaria se tomará de las anotaciones de la clase Empleado.

El resultado final se verá así:

@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 Uso de join en HQL

Y ahora veamos cómo escribir consultas a entidades relacionadas en HQL.

Primera situación.

Tenemos un empleado (Empleado) y queremos obtener una lista de sus tareas. Así es como se vería esa consulta en SQL:

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

Y ahora escribamos la misma consulta en HQL:

from EmployeeTask where employee.name = "Ivan Ivanovich"

La clase EmployeeTask tiene un campo de empleado y un campo de nombre , por lo que esta consulta funcionará.

Situación dos.

Devolver una lista de empleados que tienen tareas atrasadas. Así es como se vería esa consulta en SQL:

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

DISTINCTse utiliza porque puede haber muchas tareas asignadas a un usuario.

Y ahora escribamos la misma consulta en HQL:

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

empleado en esta consulta es un campo de la clase EmployeeTask

Situación tres.

Asigne todas las tareas no asignadas al director. La consulta SQL se verá así:

UPDATE task SET employee_id = 4 WHERE employee_id IS NULL

Y ahora escribamos la misma consulta en HQL:

update EmployeeTask set employee = :user where employee is null

La última consulta es la más difícil. Necesitamos pasar el ID, director, pero la clase EmployeeTask no contiene un campo donde pueda escribir id, sino que contiene un campo de Empleado donde debe asignar una referencia a un objeto de tipo Empleado.

En Hibernate, este problema se resuelve con la ayuda de los parámetros de consulta que se pasan al objeto Query. Y en el propio HQL, dichos parámetros se escriben mediante dos puntos: :user. Pero hablaremos de esto un poco más tarde.