2.1 Vinculación a nivel de tabla

Hemos visto como Hibernate almacena colecciones en tablas auxiliares. Ahora averigüemos cómo organizar las relaciones entre tablas completas que almacenan clases de entidades reales.

Hay cuatro tipos de relaciones entre las clases de Entidad en Hibernate:

  • uno a uno
  • uno a muchos
  • muchos -a- uno
  • muchos -a- muchos

Y comenzaremos el análisis con la opción más simple: muchos a uno .

Ya se ha encontrado con una relación de este tipo entre tablas en SQL. Así es como suele verse:

identificación nombre ocupación salario edad Fecha de Ingreso
1 ivanov ivan Programador 100000 25 2012-06-30
2 petrov petr Programador 80000 23 2013-08-12
3 Sergey Ivanov Ensayador 40000 treinta 2014-01-01
4 Rabinovich Moisha Director 200000 35 2015-05-12
5 Anastasia Kirienko Gerente de oficina 40000 25 2015-10-10
6 Vaska Gato 1000 3 2018-11-11

mesa de empleados:

Esta tabla tiene las siguientes columnas:

  • identificación INT
  • nombre VARCHAR
  • ocupación VARCHAR
  • salario INT
  • edad INT
  • unirse_fecha FECHA

Y así es como se ve la tabla de tareas , que contiene tareas para los empleados:

identificación ID de empleado nombre fecha límite
1 1 Arreglar un error en la interfaz 2022-06-01
2 2 Arreglar un error en el backend 2022-06-15
3 5 comprar cafe 2022-07-01
4 5 comprar cafe 2022-08-01
5 5 comprar cafe 2022-09-01
6 (NULO) limpiar la oficina (NULO)
7 4 Disfruta la vida (NULO)
8 6 Disfruta la vida (NULO)

Esta tabla tiene solo 4 columnas:

  • id : número de tarea único (y filas en la tabla);
  • employee_id : ID de empleado de la tabla de empleados a la que se asigna la tarea;
  • nombre – nombre y descripción de la tarea;
  • fecha límite : el tiempo en el que se debe completar la tarea.

Vemos que muchas filas en la tabla de tareas pueden hacer referencia a una sola entrada en la tabla de empleados. Esta relación a nivel de tabla se llama muchos a uno.

2.2 Relación con el nivel de clase de Java

Además de la comunicación a nivel de tabla, también puede organizar la comunicación a nivel de clases de Entidad en Hibernate. Esto se hace con una anotación @ManyToOne.

Pero primero, creemos dos clases: Employee y EmployeeTask :


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String name;
 
   @Column(name="occupation")
   public String occupation;
 
   @Column(name="salary")
   public Integer salary;
 
   @Column(name="join_date")
   public Date join;
}

Y una segunda clase para almacenar trabajos de empleados:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
  @Column(name="employee_id")
   public Integer employeeId;
 
   @Column(name="deadline")
   public Date deadline;
}

Todo está bien con estas clases, pero no existe una relación entre ellas que refleje el hecho de que el campo employeeId de la clase EmployeeTask se refiere al campo id de la clase Employee. es hora de arreglarlo

2.3 Anotación @ManyToOne.

Primero, en Java estamos acostumbrados a operar sobre objetos (y referencias a objetos) en lugar de su id. En primer lugar, en lugar del campo employeeId en la clase EmployeeTask, apuntemos a un objeto de tipo Empleado. Así es como se verá nuestra nueva clase:


@Entity
@Table(name="task")
class EmployeeTask {
   @Column(name="id")
   public Integer id;
 
   @Column(name="name")
   public String description;
 
   @ManyToOne
   @JoinColumn(name = "employee_id")
   public Employee employee;
 
   @Column(name="deadline")
   public Date deadline;
}

Con la ayuda de la anotación @ManyToOne , hemos indicado que muchos objetos EmployeeTask pueden hacer referencia a un objeto de tipo Employee. Además, usando la anotación @JoinColumn , indicamos en qué columna de nuestra tabla se almacena el id del objeto Empleado.

2.4 Solicitar ejemplos

Y ahora mostremos algunos ejemplos de cómo Hibernate puede funcionar con clases relacionadas.

escenario uno

Escribamos una consulta para averiguar todas las tareas que se han asignado a un usuario específico. Así es como se vería esta consulta en HQL:

from EmployeeTask where employee.name = "Ivan Ivanovich"

Simplemente puede hacer referencia a campos de clases dependientes a través de un punto. Es muy cómodo. Pero sigamos escribiendo esta consulta en forma de código Java:


String hql = "from EmployeeTask where employee.name = :username";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter("username", "Ivan Ivanovich");
List<EmployeeTask> resultLIst = query.list();

escenario dos

Escribamos una consulta que devuelva una lista de empleados que tienen tareas atrasadas. Una tarea está vencida si su fecha límite está en el pasado. 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();

El 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 la identificación del director, pero la clase EmployeeTask no contiene un campo donde podamos escribir una identificación, sino que contiene un campo Empleado donde debemos asignar una referencia a un objeto de tipo Empleado.


Employee director = session.get(Employee.class, 4);
 
String hql = "update EmployeeTask set employee = :user where employee is null";
Query<EmployeeTask> query = session.createQuery(hql, EmployeeTask.class);
query.setParameter("user", director);
query.executeUpdate();