HowToDoInJava

  • Java 8
  • Regex
  • Concurrency
  • Best Practices
  • Spring Boot
  • JUnit5
  • Interview Questions

Hibernate One to One Mapping Annotation Example

By Lokesh Gupta | Filed Under: Hibernate

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.

  1. First technique is most widely used and uses a foreign key column in one of the tables.
  2. Second technique uses a rather known solution of having a third table to store mapping between first two tables.
  3. 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:

foreign key association one to one

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.

join table one to one mapping

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:

shared primary key one to one

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 !!

Download source code

About Lokesh Gupta

Founded HowToDoInJava.com in late 2012. I love computers, programming and solving problems everyday. A family guy with fun loving nature. You can find me on Facebook, Twitter and Google Plus.

Feedback, Discussion and Comments

  1. Alex

    January 5, 2018

    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!

    Reply
  2. sarathkumar reddy

    December 10, 2017

    User.java
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
    private Set<Address> userAddresses = new HashSet<Address>();
    
    Address.java
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="UserID")
    private User user;
    

    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

    Reply
  3. Valentino

    March 19, 2017

    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

    Reply
  4. Vikas

    February 27, 2017

    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.

    Reply
  5. Shiva kumar

    November 1, 2016

    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?

    Reply
  6. Juan Pablo Angamarca

    July 20, 2016

    Superb tutorial, was of great help to implement the one to one relationships in my application’s datamodel. Thanks a lot, keep rocking.

    Reply
  7. savita

    March 30, 2016

    thanks , good explanation. Can you please modify the same example to add one new column in newly created table.

    Reply
    • Lokesh Gupta

      March 30, 2016

      Never tried this. I will try in my free time.

      Reply
      • savita

        April 4, 2016

        thanks but I got How to do it…
        I am pasting my example here…

        1) AccountEntity.java

        package com.hbm;
        
        import java.io.Serializable;
        import java.util.HashSet;
        import java.util.Set;
        
        import javax.persistence.Column;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.GenerationType;
        import javax.persistence.Id;
        import javax.persistence.OneToMany;
        import javax.persistence.Table;
        import javax.persistence.UniqueConstraint;
        
        
        @Entity(name = "JoinTableAccountEntity")
        @Table(name = "ACCOUNT", uniqueConstraints = {
        @UniqueConstraint(columnNames = "ID")})
        public class AccountEntity implements Serializable
        {
        
           private static final long serialVersionUID = -6790693372846798580L;
        
           @Id
           @GeneratedValue(strategy = GenerationType.IDENTITY)
           @Column(name = "ID", unique = true, nullable = false)
           private Integer accountId;
        
           @Column(name = "ACC_NUMBER", unique = true, nullable = false, length = 100)
           private String accountNumber;
           
           public AccountEntity( String accountNumber) {
        	super();
        	this.accountNumber = accountNumber;
        }
        
        @OneToMany(mappedBy = "accountentity")
           private Set empaccdetail= new HashSet();
        
           public Set getEmpaccdetail() {
        	return empaccdetail;
        }
        
        public void setEmpaccdetail(Set empaccdetail) {
        	this.empaccdetail = empaccdetail;
        }
        
        public Integer getAccountId() {
               return accountId;
           }
        
           public void setAccountId(Integer accountId) {
               this.accountId = accountId;
           }
        
           public String getAccountNumber() {
               return accountNumber;
           }
        
           public void setAccountNumber(String accountNumber) {
               this.accountNumber = accountNumber;
           }
        }
        

        2)EmployeeEntity.java

        package com.hbm;
        import java.io.Serializable;
        import java.util.Set;
        
        import javax.persistence.CascadeType;
        import javax.persistence.Column;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.GenerationType;
        import javax.persistence.Id;
        import javax.persistence.JoinColumn;
        import javax.persistence.JoinTable;
        import javax.persistence.OneToMany;
        import javax.persistence.Table;
        import javax.persistence.UniqueConstraint;
         
        @Entity
        @Table(name = "Employee", uniqueConstraints = {
        @UniqueConstraint(columnNames = "ID"),
        @UniqueConstraint(columnNames = "EMAIL") })
        public class EmployeeEntity implements Serializable
        {
            private static final long serialVersionUID = -1798070786993154676L;
         
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "ID", unique = true, nullable = false)
            private Integer employeeId;
         
            public EmployeeEntity(String email, String firstName,
        			String lastName) {
        		super();
        		this.email = email;
        		this.firstName = firstName;
        		this.lastName = lastName;
        	}
        
        	@Column(name = "EMAIL", unique = true, nullable = false, length = 100)
            private String email;
         
            @Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
            private String firstName;
         
            @Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
            private String lastName;
         
            @OneToMany( mappedBy="accountentity")
            private Set empaccdetail;
         
            public Integer getEmployeeId() {
                return employeeId;
            }
         
            public void setEmployeeId(Integer employeeId) {
                this.employeeId = employeeId;
            }
         
            public String getEmail() {
                return email;
            }
         
            public void setEmail(String email) {
                this.email = email;
            }
         
            public String getFirstName() {
                return firstName;
            }
         
            public void setFirstName(String firstName) {
                this.firstName = firstName;
            }
         
            public String getLastName() {
                return lastName;
            }
         
            public void setLastName(String lastName) {
                this.lastName = lastName;
            }
        
        	public Set getEmpaccdetail() {
        		return empaccdetail;
        	}
        
        	public void setEmpaccdetail(Set empaccdetail) {
        		this.empaccdetail = empaccdetail;
        	}
        }
        

        3)EmpAcc.java (bean for joined table)

        package com.hbm;
        
        import javax.persistence.CascadeType;
        import javax.persistence.Column;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.Id;
        import javax.persistence.JoinColumn;
        import javax.persistence.ManyToOne;
        import javax.persistence.Table;
        
        @Entity
        @Table(name = "Emp_Acc")
        public class EmpAcc 
        {
        	@Id
        	 @GeneratedValue
        	@Column(name="EMP_ACC_ID")
        		private long emp_acc_id;
        	
        	@ManyToOne(cascade = CascadeType.ALL)
        	    @JoinColumn(name = "EID")  
        	    private EmployeeEntity employeeentity;
        	 
        	  @ManyToOne(cascade = CascadeType.ALL)
        	    @JoinColumn(name = "AID")
        	    private AccountEntity accountentity;
        	    public long getEmp_acc_id() {
        		return emp_acc_id;
        	}
        	public void setEmp_acc_id(long emp_acc_id) {
        		this.emp_acc_id = emp_acc_id;
        	}
        	public EmployeeEntity getEmployeeentity() {
        		return employeeentity;
        	}
        	public void setEmployeeentity(EmployeeEntity employeeentity) {
        		this.employeeentity = employeeentity;
        	}
        	public AccountEntity getAccountentity() {
        		return accountentity;
        	}
        	public void setAccountentity(AccountEntity accountentity) {
        		this.accountentity = accountentity;
        	}
        	public int getBalance() {
        		return balance;
        	}
        	public void setBalance(int balance) {
        		this.balance = balance;
        	}
        		private int  balance;
        	
        
        }
        

        4)MainClass.java

        package com.hbm;
        
        import org.hibernate.Session;
        import org.hibernate.cfg.Configuration;
         
        public class TestJoinTable
        {
            public static void main(String[] args)
            {
                Session session = new Configuration().configure("com/hbm/hibernate.cfg.xml").buildSessionFactory().openSession();
                		session.beginTransaction();
         
                		EmployeeEntity emp=new EmployeeEntity("fdsgf@fgf"," jffksjf"," fdlskf");
                		
                		AccountEntity acc=new AccountEntity("245");
                		        		
                		EmpAcc empAcc=new EmpAcc();
                		empAcc.setEmployeeentity(emp);
                		empAcc.setAccountentity(acc);
                		empAcc.setBalance(3555);
                	
           session.save(empAcc);
            System.out.println("saved ");
                session.getTransaction().commit();
        
            }
        }
        

        In the above example balance is the new column.

        Reply
        • Lokesh Gupta

          April 4, 2016

          Thanks for sharing your solution. Much appreciated.

          Reply
          • savita

            April 5, 2016

            Welcome….do you know gwt?

            Reply
            • Lokesh Gupta

              April 5, 2016

              Never tried

              Reply
  8. savita

    March 30, 2016

    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

    Reply
  9. sunking

    January 29, 2016

    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

    Reply
    • Lokesh Gupta

      January 29, 2016

      This will help you : https://howtodoinjava.com/hibernate/how-to-define-association-mappings-between-hibernate-entities/

      Reply
      • sunking

        February 10, 2016

        Thank you

        Reply
  10. Velayudham

    December 22, 2015

    How to insert data into database using annotation

    Reply
  11. Suman

    December 7, 2015

    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)

    Reply
  12. Ravi

    December 4, 2015

    Its great site to learn java. Thanks a lot Keep it up…………..

    Reply
  13. ashutosh singh

    September 23, 2015

    Great Explanation….Thanks..Sir Keep it up …

    Reply
  14. lokesh

    September 16, 2014

    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

    Reply
    • Lokesh

      September 16, 2014

      Similar example is discussed in one to many mapping tutorial

      private Set accounts;

      Reply
  15. Mahadev Shinde

    June 7, 2014

    Awsome explanation…. bookmarking site. Thanks

    Reply
  16. Amine

    February 6, 2014

    big Thank’s for your HELP

    Reply
  17. chandu

    December 13, 2013

    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

    Reply
    • Lokesh Gupta

      December 13, 2013

      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).

      Reply
  18. Senthil Muthiah

    September 23, 2013

    Hi
    Can you please help me in
    https://stackoverflow.com/questions/18895585/hibernate-version-annotation-and-object-references-an-unsaved-transient-instanc

    Reply
  19. Abhisek

    July 21, 2013

    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.

    Reply
    • Lokesh Gupta

      July 21, 2013

      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. [:-)]

      Reply
  20. Vishal

    July 5, 2013

    Wonderful information captured in one place. This blog is awesome.

    Reply
  21. ravi

    July 2, 2013

    Great post. Thanks for sharing the concepts.

    Reply
  22. Anonymous

    May 22, 2013

    Thanks for the article, it was to much helpful thankls a lot!!!!

    Reply
  23. aravind

    November 15, 2012

    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

    Reply
    • Admin

      November 15, 2012

      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 !!

      Reply

Ask Questions & Share Feedback Cancel reply

Your email address will not be published. Required fields are marked *

*Want to Post Code Snippets or XML content? Please use [java] ... [/java] tags otherwise code may not appear partially or even fully. e.g.
[java] 
public static void main (String[] args) {
...
}
[/java]

Search Tutorials

  • Email
  • Facebook
  • RSS
  • Twitter

Hibernate Tutorial

  • Hibernate – Introduction
  • Hibernate – Hello World
  • Hibernate – Get/Fetch
  • Hibernate – Persist
  • Hibernate – Merge & Refresh
  • Hibernate – Get Entity Reference
  • Hibernate – BLOB
  • Hibernate – Save Update
  • Hibernate – Persistence LifeCycle
  • Hibernate – SessionFactory
  • Hibernate – Entities Equality
  • Hibernate – Cascade Types
  • Hibernate – Lazy Loading
  • Hibernate – Criteria Queries
  • Hibernate – HQL
  • Hibernate – Named Query
  • Hibernate – Mappings
  • Hibernate – First Level Cache
  • Hibernate – Second Level Cache
  • Hibernate – EhCache Configuration
  • Hibernate – OSCache Configuration
  • Hibernate – C3P0 Connection Pool
  • Hibernate – In memory Database
  • Hibernate – Bean Validation
  • Hibernate – Validator CDI
  • UnexpectedTypeException

Hibernate Annotations

  • Hibernate – JPA 2 Annotations
  • Annotations Vs Mappings
  • Hibernate – @Immutable
  • Hibernate – @NaturalId
  • Hibernate – @OneToMany
  • Hibernate – @ManyToMany
  • Hibernate – @OneToOne

Popular Tutorials

  • Java 8 Tutorial
  • Core Java Tutorial
  • Java Collections
  • Java Concurrency
  • Spring Boot Tutorial
  • Spring AOP Tutorial
  • Spring MVC Tutorial
  • Spring Security Tutorial
  • Hibernate Tutorial
  • Jersey Tutorial
  • Maven Tutorial
  • Log4j Tutorial
  • Regex Tutorial

Meta Links

  • Advertise
  • Contact Us
  • Privacy policy
  • About Me

Copyright © 2016 · HowToDoInjava.com · All Rights Reserved. | Sitemap