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();