Hibernate one-to-one mapping using annotations
If you are working on any hibernate project or you are planning to work on any in future, then you can easily understand the one-to-one relationships between several entities in your application. In this post, i will discuss variations of one-to-one mappings supported in hibernate.
Download source code
Sections in this post:
Various supported techniques
Using foreign key association
Using a common join table
Using shared primary key
For this article, I am extending the example written
for hello world example. We have two entities here:
Employee and
Account.
Various supported techniques
In hibernate there are 3 ways to create one-to-one relationships between two entities. Either way you have to use
@OneToOne annotation.
First technique is most widely used and uses a foreign key column in one to table.
Second technique uses a rather known solution of having a third table to store mapping between first two tables.
Third technique is something new which uses a common primary key value in both the tables.
Lets see them in action one by one:
Using foreign key association
In this association, a foreign key column is created in owner entity. For example, if we make EmployeeEntity owner, then a extra column “ACCOUNT_ID” will be created in Employee table. This column will store the foreign key for Account table.
Table structure will be like this:
To make such association, refer the account entity in EmployeeEntity class as follow:
1.
@OneToOne
2.
@JoinColumn
(name=
"ACCOUNT_ID"
)
3.
private
AccountEntity account;
The join column is declared with the
@JoinColumn annotation which looks like the
@Column annotation. It has one more parameters named referencedColumnName. This parameter declares the column in the targeted entity that will be used to the join.
If no @JoinColumn is declared on the owner side, the defaults apply. A join column(s) will be created in the owner table and its name will be the concatenation of the name of the relationship in the owner side, _ (underscore), and the name of the primary key column(s) in the owned side.
In a bidirectional relationship, one of the sides (and only one) has to be the owner: the owner is responsible for the association column(s) update.
To declare a side as not responsible for the relationship, the attribute mappedBy is used. mappedBy refers to the property name of the association on the owner side.
1.
@OneToOne
(mappedBy=
"account"
)
2.
private
EmployeeEntity employee;
Above “mappedBy” attribute declares that it is dependent on owner entity for mapping.
Lets test above mappings in running code:
01.public class TestForeignKeyAssociation {
03. public static void main(String[] args) {
04. Session session = HibernateUtil.getSessionFactory().openSession();
05. session.beginTransaction();
06.
07. AccountEntity account = new AccountEntity();
08. account.setAccountNumber("123-345-65454");
09.
10. // Add new Employee object
11. EmployeeEntity emp = new EmployeeEntity();
12. emp.setEmail("demo-user@mail.com");
13. emp.setFirstName("demo");
14. emp.setLastName("user");
15.
16. // Save Account
17. session.saveOrUpdate(account);
18. // Save Employee
19. emp.setAccount(account);
20. session.saveOrUpdate(emp);
21.
22. session.getTransaction().commit();
23. HibernateUtil.shutdown();
24. }
25.}
Running above code creates desired schema in database and run these SQL queries.
1.
Hibernate:
insert
into
ACCOUNT (ACC_NUMBER)
values
(?)
2.
Hibernate:
insert
into
Employee (ACCOUNT_ID, EMAIL, FIRST_NAME, LAST_NAME)
values
(?, ?, ?, ?)
You can verify the data and mappings in both tables when you run above program..
Using a common join table
This approach is not new to all of us. Lets start with targeted DB structure in this technique.
In this technique, main annotation to be used is
@JoinTable.
This annotation is used to define the new table name (mandatory) and foreign keys from both of the tables. Lets see how it is used:
1.
@OneToOne
(cascade = CascadeType.ALL)
2.
@JoinTable
(name=
"EMPLOYEE_ACCCOUNT"
, joinColumns =
@JoinColumn
(name=
"EMPLOYEE_ID"
),
3.
inverseJoinColumns =
@JoinColumn
(name=
"ACCOUNT_ID"
))
4.
private
AccountEntity account;
@JoinTable annotation is used in EmployeeEntity class. It declares that a new table EMPLOYEE_ACCOUNT will be created with two columns EMPLOYEE_ID (primary key of EMPLOYEE table) and ACCOUNT_ID (primary key of ACCOUNT table).
Testing above entities generates following SQL queries in log files:
1.
Hibernate:
insert
into
ACCOUNT (ACC_NUMBER)
values
(?)
2.
Hibernate:
insert
into
Employee (EMAIL, FIRST_NAME, LAST_NAME)
values
(?, ?, ?)
3.
Hibernate:
insert
into
EMPLOYEE_ACCCOUNT (ACCOUNT_ID, EMPLOYEE_ID)
values
(?, ?)
Using shared primary key
In this technique, hibernate will ensure that
it will use a common primary key value in both the tables. This way primary key of EmployeeEntity can safely be assumed the primary key of AccountEntity also.
Table structure will be like this:
In this approach,
@PrimaryKeyJoinColumn is the main annotation to be used.Let see how to use it.
1.
@OneToOne
(cascade = CascadeType.ALL)
2.
@PrimaryKeyJoinColumn
3.
private
AccountEntity account;
In AccountEntity side, it will remain dependent on owner entity for the mapping.
1.
@OneToOne
(mappedBy=
"account"
, cascade=CascadeType.ALL)
2.
private
EmployeeEntity employee;
Testing above entities generates following SQL queries in log files:
1.
Hibernate:
insert
into
ACCOUNT (ACC_NUMBER)
values
(?)
2.
Hibernate:
insert
into
Employee (ACCOUNT_ID, EMAIL, FIRST_NAME, LAST_NAME)
values
(?, ?, ?, ?)
So, we have seen all 3 types of one to one mappings supported in hibernate. I will suggest you to download the source code and play with it.
Happy Learning !!
Source:
http://howtodoinjava.com/2012/11/15/hibernate-one-to-one-mapping-using-annotations/