5.1 Várias formas de comunicação um-para-um

Há outro caso interessante e bastante específico de relacionamento entre duas classes Entity - um relacionamento um-para-um.

Eu chamo esse caso de muito específico, pois é mais sobre objetos Java do que um banco de dados. No banco de dados, existem apenas duas opções para o relacionamento entre as tabelas:

  • A linha da tabela contém um link para o id de outra tabela.
  • A tabela de serviço é usada para relacionamentos muitos-para-muitos.

No caso de classes Entity, podem existir opções que são descritas por várias anotações:

  • @Integrado
  • OneToOne unilateral
  • Bilateral OneToOne
  • @MapsId

A seguir, consideraremos os mais populares deles.

5.2 Incorporado

A propósito, já consideramos a opção de comunicação um-para-um@Embedded mais simples - esta é uma anotação . Neste caso, temos duas classes armazenadas na mesma tabela do banco de dados.

Digamos que queremos armazenar o endereço do usuário na classe 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;
}

Então só precisamos adicionar um campo com este endereço na classe User :


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

O Hibernate fará o resto: os dados serão armazenados em uma tabela, mas ao escrever consultas HQL, você precisará operar nos campos da classe.

Exemplo de consulta HQL:

select from User where address.city = 'Paris'

5.3 OneToOne unilateral

Imagine agora a situação: temos uma tabela de origem funcionário e uma tarefa que se refere a funcionário. Mas sabemos com certeza que no máximo uma tarefa pode ser atribuída a um usuário. Então podemos usar a anotação para descrever esta situação @OneToOne.

Exemplo:


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

O Hibernate garantirá que não apenas uma tarefa tenha um usuário, mas também que um usuário tenha apenas uma tarefa. Caso contrário, este caso é praticamente diferente de @ManyToOne.

5.4 Bilateral OneToOne

A opção anterior pode ser um pouco inconveniente, porque muitas vezes você deseja atribuir um funcionário não apenas a uma tarefa, mas também atribuir uma tarefa a um funcionário.

Para fazer isso, você pode adicionar o campo EmployeeTask à classe Employee e fornecer as anotações corretas.


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

Importante!A tabela de funcionários não possui um campo task_id , em vez disso, o campo employee_id da tabela de tarefas é usado para estabelecer um relacionamento entre as tabelas .

Estabelecer uma conexão entre objetos é assim:


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 remover o link, os links também devem ser removidos de ambos os 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();