5.1 Diversas formas de comunicación uno a uno

Hay otro caso interesante y bastante específico de una relación entre dos clases de Entidades: una relación uno a uno.

Llamo a este caso muy específico, ya que se trata más de objetos Java que de una base de datos. En la base de datos, solo hay dos opciones para la relación entre tablas:

  • La fila de la tabla contiene un enlace a la identificación de otra tabla.
  • La tabla de servicios se utiliza para relaciones de muchos a muchos.

En el caso de las clases de Entidad, puede haber opciones que se describen mediante varias anotaciones:

  • @Incorporado
  • OneToOne unilateral
  • Uno a uno bilateral
  • @MapsId

A continuación consideraremos los más populares de ellos.

5.2 Embebido

Por cierto, ya hemos considerado la opción de comunicación uno a uno@Embedded más simple: esta es una anotación . En este caso, tenemos dos clases almacenadas en la misma tabla en la base de datos.

Digamos que queremos almacenar la dirección del usuario en la clase UserAddress :


@Embeddable
class UserAddress {
   @Column(name="user_address_country")
   public String country;
   @Column(name="user_address_city")
   public String city;
   @Column(name="user_address_street")
   public String street;
   @Column(name="user_address_home")
   public String home;
}

Luego solo necesitamos agregar un campo con esta dirección a la clase Usuario :


@Entity
@Table(name="user")
class User {
   @Column(name="id")
   public Integer id;
 
   @Embedded
   public UserAddress address;
 
   @Column(name="created_date")
   public Date createdDate;
}

Hibernate hará el resto: los datos se almacenarán en una tabla, pero al escribir consultas HQL, deberá operar en campos de clase.

Ejemplo de consulta HQL:

select from User where address.city = 'Paris'

5.3 OneToOne unilateral

Imagine ahora la situación: tenemos una tabla de origen empleado y una tarea que se refiere a empleado. Pero sabemos con certeza que se puede asignar un máximo de una tarea a un usuario. Entonces podemos usar la anotación para describir esta situación @OneToOne.

Ejemplo:


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

Hibernate se asegurará de que no solo una tarea tenga un usuario, sino también que un usuario tenga solo una tarea. De lo contrario, este caso prácticamente no es diferente de @ManyToOne.

5.4 Uno a uno bilateral

La opción anterior puede ser un poco inconveniente, porque a menudo desea asignar un empleado no solo a una tarea, sino también asignar una tarea a un empleado.

Para hacer esto, puede agregar el campo EmployeeTask a la clase Employee y darle las anotaciones correctas.


@Entity
@Table(name="employee")
class Employee {
   @Column(name="id")
   public Integer id;
 
   @OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
   private EmployeeTask task;
}

¡Importante!La tabla de empleados no tiene un campo task_id , sino que el campo employee_id de la tabla de tareas se utiliza para establecer una relación entre tablas .

Establecer una conexión entre objetos se ve así:


Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employee = director;
director.task = task;
 
session.update(task);
session.flush();

Para eliminar el enlace, también se deben eliminar los enlaces de ambos objetos:


Employee director = session.find(Employee.class, 4);
EmployeeTask task = director.task;
 
task.employee = null;
session.update(task);
 
director.task = null;
session.update(director);
 
session.flush();