Hibernate one to many mapping annotation example

Hibernate one to many mapping is made between two entities where first entity can have relation with multiple second entity instances but second can be associated with only one instance of first entity. Its 1 to N relationship.

For example, in any company an employee can register multiple bank accounts but one bank account will be associated with one and only one employee. In this hibernate one to many mapping annotation example, we will learn to make such mapping in database using hibernate.

Table of Contents

When to use one to many mapping
Hibernate one to many mapping solutions
1. Hibernate one to many mapping with foreign key association
2. Hibernate one to many mapping with join table

When to use one to many mapping

Use one to mapping to create 1..N relationship between entities or objects.

For example, we have to write two entities i.e. EmployeeEntity and AccountEntity such that multiple accounts can be associated with a single employee, but one single account can not be shared between two or more employees.

Hibernate one to many mapping solutions

This problem can be solved in two different ways.

  1. One is to have a foreign key column in account table i.e. EMPLOYEE_ID. This column will refer to primary key of Employee table. This way no two accounts can be associated with multiple employees. Obviously, account number needs to be unique for enforcing this restriction.
  2. Second approach is to have a common join table lets say EMPLOYEE_ACCOUNT. This table will have two column i.e. EMP_ID which will be foreign key referring to primary key in EMPLOYEE table and similarly ACCOUNT_ID which will be foreign key referring to primary key of ACCOUNT table.

1. Hibernate one to many mapping with foreign key association

In this approach, both entity will be responsible for making the relationship and maintaining it. EmployeeEntity should declare that relationship is one to many, and AccountEntity should declare that relationship from its end is many to one.

1.1. Design one to many mapping relationship

Lets first see the schema design.

one-to-many-association-in-hiberate-using-foreign-key-7284046

1.2. Entity classes

Write entity classes.

package hibernate.test.oneToMany.foreignKeyAsso;

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.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity(name = "ForeignKeyAssoEntity")
@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;

	@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(cascade=CascadeType.ALL)
	@JoinColumn(name="EMPLOYEE_ID")
	private Set<AccountEntity> accounts;

	//Getters and setters
}

Write AccountEntity.java.

package hibernate.test.oneToMany.foreignKeyAsso;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity(name = "ForeignKeyAssoAccountEntity")
@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;

	@ManyToOne
	private EmployeeEntity employee;

	//Getters and setters
}

1.3. Demo

package hibernate.test.oneToMany;

import hibernate.test.HibernateUtil;
import hibernate.test.oneToMany.foreignKeyAsso.AccountEntity;
import hibernate.test.oneToMany.foreignKeyAsso.EmployeeEntity;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;

public class TestForeignKeyAssociation
{

	public static void main(String[] args)
	{
		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();

		AccountEntity account1 = new AccountEntity();
		account1.setAccountNumber("Account detail 1");

		AccountEntity account2 = new AccountEntity();
		account2.setAccountNumber("Account detail 2");

		AccountEntity account3 = new AccountEntity();
		account3.setAccountNumber("Account detail 3");

		//Add new Employee object
		EmployeeEntity firstEmployee = new EmployeeEntity();
		firstEmployee.setEmail("demo-user-first@mail.com");
		firstEmployee.setFirstName("demo-one");
		firstEmployee.setLastName("user-one");

		EmployeeEntity secondEmployee = new EmployeeEntity();
		secondEmployee.setEmail("demo-user-second@mail.com");
		secondEmployee.setFirstName("demo-two");
		secondEmployee.setLastName("user-two");

		Set<AccountEntity> accountsOfFirstEmployee = new HashSet<AccountEntity>();
		accountsOfFirstEmployee.add(account1);
		accountsOfFirstEmployee.add(account2);

		Set<AccountEntity> accountsOfSecondEmployee = new HashSet<AccountEntity>();
		accountsOfSecondEmployee.add(account3);

		firstEmployee.setAccounts(accountsOfFirstEmployee);
		secondEmployee.setAccounts(accountsOfSecondEmployee);
		//Save Employee
		session.save(firstEmployee);
		session.save(secondEmployee);

		session.getTransaction().commit();
		HibernateUtil.shutdown();
	}
}

Program Output:

Hibernate: insert into Employee (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into ACCOUNT (ACC_NUMBER, employee_ID) values (?, ?)
Hibernate: insert into ACCOUNT (ACC_NUMBER, employee_ID) values (?, ?)
Hibernate: insert into Employee (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into ACCOUNT (ACC_NUMBER, employee_ID) values (?, ?)
Hibernate: update ACCOUNT set EMPLOYEE_ID=? where ID=?
Hibernate: update ACCOUNT set EMPLOYEE_ID=? where ID=?
Hibernate: update ACCOUNT set EMPLOYEE_ID=? where ID=?

2. Hibernate one to many mapping with join table

This approach uses a join table to store the associations between account and employee entities. @JoinTable annotation has been used to make this association.

2.1. Design

Lets see how the database schema will look like:

one-to-many-association-in-hiberate-using-join-table-5973305
one To Many association in hibernate using join table

2.2. Entity classes

package hibernate.test.oneToMany.joinTable;

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(name = "JoinTableEmployeeEntity")
@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;

	@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(cascade=CascadeType.ALL)
	@JoinTable(name="EMPLOYEE_ACCOUNT", joinColumns={@JoinColumn(name="EMPLOYEE_ID", referencedColumnName="ID")}
	, inverseJoinColumns={@JoinColumn(name="ACCOUNT_ID", referencedColumnName="ID")})
	private Set<AccountEntity> accounts;

	//Getters and setters
}
package hibernate.test.oneToMany.joinTable;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
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;

	//Getters and setters
}

2.3. Hibernate configuration

We have available both entities to runtime, we have to add them in hibernate.cfg.xml file. Please note that only one set of entities should be configured in configuration file otherwise unexpected results can occur.

< ?xml version="1.0" encoding="utf-8"?>
< !DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatetest</property>
		<property name="hibernate.connection.password">XXXXXX</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		<property name="show_sql">true</property>
		<property name="hbm2ddl.auto">create</property>
		<mapping clas="hibernate.test.oneToMany.foreignKeyAsso.AccountEntity"></mapping>
		<mapping clas="hibernate.test.oneToMany.foreignKeyAsso.EmployeeEntity"></mapping>
	</session-factory>
</hibernate-configuration>

2.4. Demo

Now, its time to test the code. I have written following code to test above entities.

package hibernate.test.oneToMany;

import hibernate.test.HibernateUtil;
import hibernate.test.oneToMany.joinTable.AccountEntity;
import hibernate.test.oneToMany.joinTable.EmployeeEntity;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;

public class TestJoinTable
{
	public static void main(String[] args)
	{
		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();

		AccountEntity account1 = new AccountEntity();
		account1.setAccountNumber("123-345-65454");

		AccountEntity account2 = new AccountEntity();
		account2.setAccountNumber("123-345-6542222");

		//Add new Employee object
		EmployeeEntity emp = new EmployeeEntity();
		emp.setEmail("demo-user@mail.com");
		emp.setFirstName("demo");
		emp.setLastName("user");

		Set<AccountEntity> accounts = new HashSet<AccountEntity>();
		accounts.add(account1);
		accounts.add(account2);

		emp.setAccounts(accounts);
		//Save Employee
		session.save(emp);

		session.getTransaction().commit();
		HibernateUtil.shutdown();
	}
}

Program Output:

Hibernate: insert into Employee (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?)
Hibernate: insert into ACCOUNT (ACC_NUMBER) values (?)
Hibernate: insert into EMPLOYEE_ACCOUNT (EMPLOYEE_ID, ACCOUNT_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_ACCOUNT (EMPLOYEE_ID, ACCOUNT_ID) values (?, ?)

In this hibernate one to many mapping annotation example using list, we learned to create 1..N relationships between two entities using foreign key association and join table techniques.

Happy Learning !!

Read More:

Hibernate one to one mapping annotation example
Hibernate many to many mapping annotation example

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

44 thoughts on “Hibernate one to many mapping annotation example”

  1. I had 4 tables and they are related like this:

    1st Table : Columns are username, password, is active. It has a primary key username
    2nd Table : Column are user_role_id, username, role. User_role_id is primary key and username has a foreign key constraint with 1st table (username)

    3rd Table: Columns are id, role_id, comp_id. id is primary key and role_id and comp_id has foreign key constraints with 2nd (user_role_id) and 4th table (id)

    4th Table: columns are id, component_name, component_path. id is primary key

    My problem is I want to retrieve component_name and Component_path based on username.

    How to do it in Hibernate. Plz help. Stuck for many days on this.

    Reply
  2. Hi Lokesh,

    Thanks for your wonderful tutorial!!

    I have some doubts –

    1. The foreign key association example in this post is unidirectional association or a bidirectional one. I feel it is bidirectional as
    both the entities have reference to each other.

    2. In case it is bidirectional then why have we not made the Account entity as the owner of the
    relation. Why is “mappedBy” attribute not used?

    Thanks in advance,

    Rohit

    Reply
  3. Hi Lokesh Gupta,
    Thanks for the post.
    This work good for save,Update,delete,get(EmployeeEntity.class,id), but in Query.list() gives Error like this

    Hibernate: select employeeen0_.ID as ID0_0_, employeeen0_.EMAIL as EMAIL0_0_, employeeen0_.FIRST_NAME as FIRST3_0_0_, employeeen0_.LAST_NAME as LAST4_0_0_ from Employee employeeen0_ where employeeen0_.ID=?
    org.hibernate.hql.ast.QuerySyntaxException: EmployeeEntity is not mapped [from EmployeeEntity]

    can help me to fatch all Records from EmployeeEntity Table with Account details.

    Reply
  4. Hi Lokesh,
    nice explanation!!
    I have a doubt regarding account class.Nowhere you are mentioning save account object then how it is saving the account object.
    please clarify!!

    Reply
  5. Hi,

    I am not quite clear why did you use Set accounts; on EmployeeEntity? everybody uses set on OneToMany relationship is there a specific reason for it?

    thanks

    Reply
    • we can use any collection implementation like set or list, no limitations to set , but we generally use set because set takes no duplicate values so if any account is added twice it might change the entire concept so here used SET.

      Reply
  6. Hi, I have seen at different places that the annotations are placed above the getter methods. Does it make a difference if we place the annotations above the getter methods?

    Reply
  7. Thanks for the great article.

    When would be the behaivor if i add the mappedBy annotation to the end of one entiy ?

    Reply
  8. With reference to implementation of REST Api using Spring, In above given link, there are some test call say “TestForeignKeyAssociation” and “TestJoinTable”. Where do I mention this code in my application? How shall I pass two objects as request body? Do I really need to send two objects as request body? What approach shall I follow?

    Reply
      • [1] created two entity class called address and location (where LocationId is foreign key)
        [2] applied relationship in address class as “@OneToOne(cascade = CascadeType.ALL)…@JoinColumn(name = “LocationId”)…private Location location;
        [3] Now, How do I send JSON input for address and location values to controller which will further send to service and DAO class to persist?

        Reply
          • Here is an example of Spring REST. Create a POST method with request body like below:

            UserLocation {
               &quot;address&quot;: { &quot;street&quot;:&quot;data&quot;, &quot;city&quot;: &quot;data&quot;},
                &quot;location&quot;: { &quot;field1&quot;:&quot;data&quot;, &quot;field2&quot;: &quot;data&quot;},
            }

            In controller, parse this object and populate separate Location and Address entities, and store them using hibernate.

          • To parse this object, do I need to create a separate POJO (consist both address and location variables) for the same or do I just parse it as JSON and fetch it using JSONObject?

          • Thanks !! Anyways nice post.
            Can you provide some reference to implement REST API using spring security? (like, user login, limited access of information, etc…)

  9. How do I apply the same logic for Spring REST api application. Like, logic implemented in HibernateStandAlone will be applied at where? How do I take two objects as an Input? Do I really need to take input of two object or one will be sufficient?

    Reply
  10. Hi Lokesh,

    I am little confused after reading the above post. I guess this is related to Unidirectional association only. Do you have any good link for bidirectional OneToMany association?

    Thanks,
    Anurag.

    Reply
  11. Hi ….Lokesh ,
    I Dont know anout hibernate i am create database with one to many and many to one mapped table
    Tbl_FileMaster (File_id,filename,filepath) joincolumn fileid
    Tbl_Header_Master(id,header,(fileid)—/joincolumn) created now i want to use inner join on it so is it possiable to create such query in this senario

    select header with max(fileid) in Filemaster table …..
    Need Help
    Thanks !

    Reply
  12. Hi Lokesh,

    Can you please explain more about inverse property.

    I have idea how to define in entity hbm.XML file, but I am confused in case of annotations.
    I want to know how we decide about the Relationship owned in case of annotations based config.

    Thanks in advance.

    Reply
  13. Hi Lokesh, Thanks for the nice post. I have some query regarding, I have to make composite primary key in table B which is combination of B_id ,first_id without using Embedded Id.So,Is there any way to do this without creating any extra class.
    ——-
    TABLE_A
    ——-
    A_id (pk)
    [other fields]

    ——-
    TABLE_B
    ——-
    B_id
    first_id (fk TABLE_A.A_id)
    PRIMARY KEY (B_id, first_id)
    [other fields]

    Reply
    • @id
      @manytoone(“your column name”)
      declare your referenced class object like “Device device”

      @id
      @manytoone(“anothe column”)
      object anothe class that u have to mapped

      it just simple its work for me

      Reply
  14. Hi Lokesh,

    First of all thanks for putting the effort for creating the various tutorials on java.

    Now onto the question. How to get EmployeeEntity associated with AccountEntity when using jointable. Would I be able to do a @ManyToOne annotation on a field inside AccountEntity like in the example using foreign key association?

    Thanks,
    -aru

    Reply
  15. I don’t understand as to why following entries were added in hibernate.cfg.xml file

    We have already annotated the entity with mapping information.

    Reply
  16. Hi Lokesh,
    Finally,I have completed your Hibernate tutorial.I am very grateful to you.I need another assistance from you.Please provide some examples with real time scenarios struts with Hibernate integration using log4j,ANT tools..

    Reply
  17. Dear Lokesh..I worked out your example(Using a join table) its works great…iam totally new to hibernate..i used hibernate tools to generate annotated files..but its totally different…any way i over come that issue.my only question is
    how can i generate annotated file like you(specified in above example) ?pls reply iam very much comfortable with your example…

    Reply
  18. Dear Lokesh
    I am getting following ExceptionInInitializerError
    what should I do?

    Initial SessionFactory creation failed.java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
    Exception in thread “main” java.lang.ExceptionInInitializerError
    at hibernate.test.HibernateUtil.buildSessionFactory(HibernateUtil.java:22)
    at hibernate.test.HibernateUtil.(HibernateUtil.java:10)
    at hibernate.test.oneToMany.TestJoinTable.main(TestJoinTable.java:17)
    Caused by: java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
    at org.hibernate.cfg.Configuration.(Configuration.java:110)
    at hibernate.test.HibernateUtil.buildSessionFactory(HibernateUtil.java:15)
    … 2 more

    Reply
  19. Hi, Lokesh
    Thanks for the post.
    If i want to update the employee entity by adding new account(‘b’) for an employee.how to go about it, in case of using join table.
    What happens to the records(‘a’ account for employee e1) in Account table. How do we delete them.

    Reply
    • let me reply based on what i understood.

      you want to assign a new account to employee. so do like this:

      1) read an employee entity from session.
      2) add newly created account object to set of accounts.
      3) finally use saveOrUpdate() method from session.

      there is no need to delete any previous record. hibernate is smart enough to differentiate between attached and detached entities.

      Reply

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.