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

undefined
1
Task
Module 4. Working with databases, level 13, lesson 4
Locked
OneToOne
task1307