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 hibernate one to one mapping example, We will discuss 3 different variations of this mapping supported by hibernate.
Table fo contents Various supported techniques for one to one mapping 1. Using foreign key association 2. Using common join table 3. Using shared primary key
For this hibernate one to one mapping example, I am extending the example written for hibernate hello world example. We have two entities here: Employee
and Account
.
An employee can have one account. Similarily, an account will be associated with one employee only. It’s one to one relationship for this example.
Various supported techniques
In hibernate there are 3 ways to create one-to-one relationships between two entities. Either way we have to use @OneToOne annotation.
- First technique is most widely used and uses a foreign key column in one of the tables.
- 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.
1. Hibernate one to one mapping with foreign key association
In this kind of 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:
@OneToOne @JoinColumn(name="ACCOUNT_ID") 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.
@OneToOne(mappedBy="account") private EmployeeEntity employee;
Above “mappedBy” attribute declares that it is dependent on owner entity for mapping.
Lets test above mappings in running code:
public class TestForeignKeyAssociation { public static void main(String[] args) { Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); AccountEntity account = new AccountEntity(); account.setAccountNumber("123-345-65454"); // Add new Employee object EmployeeEntity emp = new EmployeeEntity(); emp.setEmail("demo-user@mail.com"); emp.setFirstName("demo"); emp.setLastName("user"); // Save Account session.saveOrUpdate(account); // Save Employee emp.setAccount(account); session.saveOrUpdate(emp); session.getTransaction().commit(); HibernateUtil.shutdown(); } }
Running above code creates desired schema in database and run these SQL queries.
Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?) 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.
2. Hibernate one to one mapping with 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:
@OneToOne(cascade = CascadeType.ALL) @JoinTable(name="EMPLOYEE_ACCCOUNT", joinColumns = @JoinColumn(name="EMPLOYEE_ID"), inverseJoinColumns = @JoinColumn(name="ACCOUNT_ID")) 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:
Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?) Hibernate: insert into Employee (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?) Hibernate: insert into EMPLOYEE_ACCCOUNT (ACCOUNT_ID, EMPLOYEE_ID) values (?, ?)
3. Hibernate one to one mapping with 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.
@OneToOne(cascade = CascadeType.ALL) @PrimaryKeyJoinColumn private AccountEntity account;
In AccountEntity side, it will remain dependent on owner entity for the mapping.
@OneToOne(mappedBy="account", cascade=CascadeType.ALL) private EmployeeEntity employee;
Testing above entities generates following SQL queries in log files:
Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?) Hibernate: insert into Employee (ACCOUNT_ID, EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?, ?)
So, we have seen all 3 different ways to create one to one mapping supported in hibernate. I will suggest you to download the source code and play with it.
Happy Learning !!
Alex
Wonderful explanation!
You wrote a great article. Earlier I spent a lot of time studying this topic but I did not understand it. Thank you!
sarathkumar reddy
In OneToMany relation, the many side is the owner of the relation right ? but by specifying mappedBy=user we are saying that User is the owning entity.why?
Can you please explain the above concept ?
for bi directional rules check oracle documentation:https://docs.oracle.com/cd/E19798-01/821-1841/bnbqj/index.html
Valentino
Hi. I have a question about @OneToOne(cascade = CascadeType.ALL) when you implement “Using a common join table”. In this case, the cascade is on the side of EmployeeEntity. But I wonder, if the mappedby is in AccountEntity, then EmployeeEntity has a foreign key in AccountEntity, and I expect that removing, for example, a record from AccountEntity, the removal will be cascaded also in EmployeeEntity. So, shouldn’t the cascade be on the side of AccountEntity, where you also have the mapped by? Thanks for these great tutorials.
Valentino
Vikas
In your “mappedBy” example no foreign key relationship maintained by EmployeeEntity. Even there is no relationship between both table . You can cross verify your sql query above. i.e.
Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?)
Hibernate: insert into Employee (ACCOUNT_ID, EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?, ?)
there is no update query for foreign key.
Please clarify?
I think @JoinColumn instead of @PrimaryKeyJoinColumn is better choice.
Shiva kumar
Hi,
I tried foreign key column model, my question is why hibernate creates join table ’employee_acccount’ and have no use in one to one association. can any one clear my doubt?
Juan Pablo Angamarca
Superb tutorial, was of great help to implement the one to one relationships in my application’s datamodel. Thanks a lot, keep rocking.
savita
thanks , good explanation. Can you please modify the same example to add one new column in newly created table.
Lokesh Gupta
Never tried this. I will try in my free time.
savita
thanks but I got How to do it…
I am pasting my example here…
1) AccountEntity.java
2)EmployeeEntity.java
3)EmpAcc.java (bean for joined table)
4)MainClass.java
In the above example balance is the new column.
Lokesh Gupta
Thanks for sharing your solution. Much appreciated.
savita
Welcome….do you know gwt?
Lokesh Gupta
Never tried
savita
your example is good one but i want one additional column in a newly created join table (employee_account) Can you please modify this example to add extra column
sunking
Hi ,
Can you please elobarate on mappedBy attribute.
Could not understand, even I searched so many sites.
mappedby definition says ‘I am not the owner side and mapped by other entity’
From the given example(Employee and Account) with below code.
@OneToOne(mappedBy=”account”)
private EmployeeEntity employee;
Who is not the owner? and who is Owner and what is does actually.
Please explains
Lokesh Gupta
This will help you : https://howtodoinjava.com/hibernate/how-to-define-association-mappings-between-hibernate-entities/
sunking
Thank you
Velayudham
How to insert data into database using annotation
Suman
Was learning Hibernate and went through so many tutorials online. Completely misunderstood the functionality of mappedBy till i came across this article. Good stuff guys, keep up the good work (Y)
Ravi
Its great site to learn java. Thanks a lot Keep it up…………..
ashutosh singh
Great Explanation….Thanks..Sir Keep it up …
lokesh
i need a help,
we have a list as field to store it in data base,
for this we have to use hibernate annotations mapping class(no hibernate mapping file should be used), pojo class object contains some fields as List, those fileds will be inserted into db as string by mapping class. if possible for you, give an example
Lokesh
Similar example is discussed in one to many mapping tutorial
private Set accounts;
Mahadev Shinde
Awsome explanation…. bookmarking site. Thanks
Amine
big Thank’s for your HELP
chandu
HI Lokesh,
Good after noon,
Currently i am working with hibernate 3. i have been trying to develop a simple hibernate project with one to many relationship.every thing is fine but i am getting error like. i have placed cfg.xml file under src folder.is correct. why i am getting error. please suggest me. as soon as…..
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
Initial SessionFactory creation failed.org.hibernate.HibernateException: could not find file: hibernate.cgf.xml
Exception in thread “main” java.lang.ExceptionInInitializerError
at com.hib.pro.HibernateUtil.buildSessionFactory(HibernateUtil.java:23)
at com.hib.pro.HibernateUtil.(HibernateUtil.java:11)
at com.hib.pro.TestForeignKeyAssociation.main(TestForeignKeyAssociation.java:19)
Caused by: org.hibernate.HibernateException: could not find file: hibernate.cgf.xml
at org.hibernate.cfg.Configuration.configure(Configuration.java:1462)
at com.hib.pro.HibernateUtil.buildSessionFactory(HibernateUtil.java:18)
… 2 more
Caused by: java.io.FileNotFoundException: hibernate.cgf.xml (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(FileInputStream.java:106)
at org.hibernate.cfg.Configuration.configure(Configuration.java:1459)
… 3 more
Lokesh Gupta
Usually src folders have filters which cause to generate only .class files in target folder or classes folder. Copy the file in resources folder. The important thing is that file should be present in target folder (war file).
Senthil Muthiah
Hi
Can you please help me in
https://stackoverflow.com/questions/18895585/hibernate-version-annotation-and-object-references-an-unsaved-transient-instanc
Abhisek
Hi Lokesh,
Good Work. But I see a flaw in the DB design of your “Using foreign key association”. In the Employee Table one can have one account shared by the multiple employees which does not make it one to one but many to one. For that you need to put Unique constraint on Account Id column in Employee Table. Please clarify.
Lokesh Gupta
Abhi, you are right. It should be implemented this way. But, also that’s not core concept for this tutorial. Mixing concepts in single post, sometimes push the core concept in back seat. Which i did not wanted to do, otherwise in any code review session, I can myself blew this code. [:-)]
Vishal
Wonderful information captured in one place. This blog is awesome.
ravi
Great post. Thanks for sharing the concepts.
Anonymous
Thanks for the article, it was to much helpful thankls a lot!!!!
aravind
Thank you sir, My name is A Aravind ,i had completed my B.Tech with an aggregate of 70%,belongs to ECE stream. Now i need to learn JAVA very effectively,i need to get placed in Java only in reputed companies. So can you please upload Core Java tutorials,JSP,SERVLETS,Struts and Hibernates. Because i am having knowledge on only Core Java,now i want to learn Struts,Hiberbates,EJB from you.
Thanking You, A.Aravind
Admin
Hello Aravind, Its good to know that you want to learn effectively. My suggestion to you is “Read more and Good”. Also, you need to learn consistently.
I will try to write some post on struts and EJBs also very soon.
By the time, if you would like to read something more in core java then follow below links: https://howtodoinjava.com/java/
https://howtodoinjava.com/best-practices/
Keep reading !!