Hibernate one-to-many mapping using annotations

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 post, we will learn to make such mapping in database using hibernate 3.

Ads by Google

Download source code

Sections in this post

Problem statement
Designing the solution
Using foreign key association
Using a join table

Problem statement

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

Designing the solution

This problem can be solved in two different ways. One is to have a foreign key column in account table i.i 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.

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

Lets write some code for both approaches.

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

Lets first see the schema design.

one To Many association in hiberate using foreign key

Lets write EmployeeEntity.java

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;

	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<AccountEntity> getAccounts() {
		return accounts;
	}

	public void setAccounts(Set<AccountEntity> accounts) {
		this.accounts = accounts;
	}
}

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;

	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;
	}

	public EmployeeEntity getEmployee() {
		return employee;
	}

	public void setEmployee(EmployeeEntity employee) {
		this.employee = employee;
	}
}

Lets Test the code:

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();
	}
}
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=?

Using a 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.

Lets see how the database schema will look like:

one To Many association in hiberate using join table

one To Many association in hibernate using join table

EmployeeEntity.java

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;

	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<AccountEntity> getAccounts() {
		return accounts;
	}

	public void setAccounts(Set<AccountEntity> accounts) {
		this.accounts = accounts;
	}
}

AccountEntity.java

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;

	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;
	}
}

Configuring entities in config file

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>

Testing the code

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

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 (?, ?)

Download source code

Happy Learning !!

Ads by Google

17 thoughts on “Hibernate one-to-many mapping using annotations”

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

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

  3. 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…

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

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

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

Note:- In comment box, please put your code inside [java] ... [/java] OR [xml] ... [/xml] tags otherwise it may not appear as intended.

Leave a Reply

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


− 5 = two

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>