5.1 Various forms of one-to-one communication
There is another interesting and rather specific case of a relationship between two Entity classes - a one-to-one relationship.
I call this case very specific, as it's more about Java objects than a database. In the database, there are only two options for the relationship between tables:
- The table row contains a link to the id of another table.
- The service table is used for many-to-many relationships.
In the case of Entity classes, there may be options that are described by several annotations:
- @Embedded
- One-sided OneToOne
- Bilateral OneToOne
- @MapsId
Below we will consider the most popular of them.
5.2 Embedded
By the way, we have already considered the simplest one-to-one@Embedded
communication option - this is an annotation . In this case, we have two classes stored in the same table in the database.
Let's say we want to store the user's address in the UserAddress class :
@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;
}
Then we just need to add a field with this address to the User class :
@Entity
@Table(name="user")
class User {
@Column(name="id")
public Integer id;
@Embedded
public UserAddress address;
@Column(name="created_date")
public Date createdDate;
}
Hibernate will do the rest: the data will be stored in one table, but when writing HQL queries, you will need to operate on class fields.
HQL query example:
select from User where address.city = 'Paris'
5.3 One-sided OneToOne
Imagine now the situation: we have a source table employee and a task that refers to employee. But we know for sure that a maximum of one task can be assigned to one user. Then we can use the annotation to describe this situation @OneToOne
.
Example:
@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 will make sure that not only one task has one user, but also that one user has only one task. Otherwise, this case is practically no different from @ManyToOne
.
5.4 Bilateral OneToOne
The previous option can be a little inconvenient, because often you want to assign an employee not only to a task, but also assign a task to an employee.
To do this, you can add the EmployeeTask field to the Employee class and give it the correct annotations.
@Entity
@Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@OneToOne(cascade = CascadeType.ALL, mappedBy="employee")
private EmployeeTask task;
}
Important!The employee table does not have a task_id field , instead the employee_id field of the task table is used to establish a relationship between tables .
Establishing a connection between objects looks like this:
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();
To remove the link, the links must also be removed from both objects:
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();
GO TO FULL VERSION