Hibernate 5 - One to Many association example

Posted on March 29, 2017


Technologies used:   JDK 1.8.0_121 | Hibernate 5.2.6.Final | Maven 3.3.9 | MySQL 5.7.12 | Eclipse Mars.2 (4.5.2)

In one-to-many association, source entity has a field that stores one or more target entities. The @OneToMany JPA annotation is used to link the source entity with the target entities.

There are two types of one-to-many association -

Unidirectional → In this type of association, only source entity has a relationship field that refers to the target entity. We can navigate this type of association from one side.

Bidirectional → In this type of association, each entity (i.e. source and target) has a relationship field that refers to each other. We can navigate this type of association from both sides.

Unidirectional one-to-many association example

Consider the following domain model and relational model diagrams of one-to-many unidirectional association.

one-to-many-uni-domain-model.png

one-to-many-uni.png

According to the above model diagrams a department can have many employees.

Jar dependencies

Add the following jar dependencies for Hibernate and MySQL in pom.xml file.

<dependencies>
  <!-- Mysql Connector -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>6.0.5</version>
  </dependency>
  <!-- Hibernate 5.2.6 Final -->
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.6.Final</version>
  </dependency>
</dependencies>

Entity class

Create two @Entity classes - Department and Employee, to map with DEPARTMENT and EMPLOYEE tables respectively.

Department.java

package com.boraji.tutorial.hibernate.entity;

import java.util.ArrayList;
import java.util.List;

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

/**
 * @author imssbora
 */
@Entity
@Table(name = "DEPARTMENT")
public class Department {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "DPT_ID")
   private long id;

   @Column(name = "NAME", nullable = false, unique = true)
   private String name;

   @OneToMany(cascade = CascadeType.ALL)
   private List<Employee> employees = new ArrayList<>();

   // Setter and Getter methods
}

Employee.java

package com.boraji.tutorial.hibernate.entity;

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

/**
 * @author imssbora
 */
@Entity
@Table(name = "EMPLOYEE")
public class Employee {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "EMP_ID")
   private long id;

   @Column(name = "NAME", nullable = false)
   private String name;

   @Column(name = "DESIGNATION")
   private String designation;

   //Setter and Getter methods
}

Hibernate utility class

Create a helper class HibernateUtil to bootstrap hibernate.

Map the Department and Employee entities using the #MetadataSources.addAnnotatedClass() method.

HibernateUtil.java

package com.boraji.tutorial.hibernate;

import java.util.HashMap;
import java.util.Map;

import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import com.boraji.tutorial.hibernate.entity.Department;
import com.boraji.tutorial.hibernate.entity.Employee;

public class HibernateUtil {
  private static StandardServiceRegistry registry;
  private static SessionFactory sessionFactory;

  public static SessionFactory getSessionFactory() {
    if (sessionFactory == null) {
      try {
        StandardServiceRegistryBuilder registryBuilder = 
            new StandardServiceRegistryBuilder();

        Map<String, String> settings = new HashMap<>();
        settings.put("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver");
        settings.put("hibernate.connection.url", "jdbc:mysql://localhost:3306/BORAJI");
        settings.put("hibernate.connection.username", "root");
        settings.put("hibernate.connection.password", "admin");
        settings.put("hibernate.show_sql", "true");
        settings.put("hibernate.hbm2ddl.auto", "update");

        registryBuilder.applySettings(settings);

        registry = registryBuilder.build();

        MetadataSources sources = new MetadataSources(registry)
            .addAnnotatedClass(Employee.class)
            .addAnnotatedClass(Department.class);

        Metadata metadata = sources.getMetadataBuilder().build();

        sessionFactory = metadata.getSessionFactoryBuilder().build();
      } catch (Exception e) {
        System.out.println("SessionFactory creation failed");
        if (registry != null) {
          StandardServiceRegistryBuilder.destroy(registry);
        }
      }
    }
    return sessionFactory;
  }

  public static void shutdown() {
    if (registry != null) {
      StandardServiceRegistryBuilder.destroy(registry);
    }
  }
}

 

Main class 

Create the MainApp class to run the application.

MainApp.java

package com.boraji.tutorial.hibernate;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.boraji.tutorial.hibernate.entity.Department;
import com.boraji.tutorial.hibernate.entity.Employee;

/**
 * @author imssbora
 */
public class MainApp {
   public static void main(String[] args) {
      Session session = null;
      Transaction transaction = null;
      try {
         session = HibernateUtil.getSessionFactory().openSession();
         transaction = session.beginTransaction();
         transaction.begin();

         Employee employee1 = new Employee();
         employee1.setName("Adam");
         employee1.setDesignation("Manager");

         Employee employee2 = new Employee();
         employee2.setName("Miller");
         employee2.setDesignation("Software Engineer");

         Employee employee3 = new Employee();
         employee3.setName("Smith");
         employee3.setDesignation("Associate  Engineer");

         Department department = new Department();
         department.setName("IT Department");
         department.getEmployees().add(employee1);
         department.getEmployees().add(employee2);
         department.getEmployees().add(employee3);

         session.persist(department);

         transaction.commit();
      } catch (Exception e) {
         if (transaction != null) {
            transaction.rollback();
         }
         e.printStackTrace();
      } finally {
         if (session != null) {
            session.close();
         }
      }
      HibernateUtil.shutdown();
   }
}

Output

Hibernate: create table DEPARTMENT (DPT_ID bigint not null auto_increment, NAME varchar(255) not null, primary key (DPT_ID))
Hibernate: create table DEPARTMENT_EMPLOYEE (Department_DPT_ID bigint not null, employees_EMP_ID bigint not null)
Hibernate: create table EMPLOYEE (EMP_ID bigint not null auto_increment, DESIGNATION varchar(255), NAME varchar(255) not null, primary key (EMP_ID))
Hibernate: alter table DEPARTMENT drop constraint UK_8ry1iwcodl3ily50pgmc89p4e
Hibernate: alter table DEPARTMENT add constraint UK_8ry1iwcodl3ily50pgmc89p4e unique (NAME)
Hibernate: alter table DEPARTMENT_EMPLOYEE drop constraint UK_a0pp6jsjn52s8caxcjoyifuvp
Hibernate: alter table DEPARTMENT_EMPLOYEE add constraint UK_a0pp6jsjn52s8caxcjoyifuvp unique (employees_EMP_ID)
Hibernate: alter table DEPARTMENT_EMPLOYEE add constraint FKmwyujamnorrw2hxkxo71sedru foreign key (employees_EMP_ID) references EMPLOYEE (EMP_ID)
Hibernate: alter table DEPARTMENT_EMPLOYEE add constraint FKtabg1wtddyrsdvjvh0vkjl09h foreign key (Department_DPT_ID) references DEPARTMENT (DPT_ID)
Hibernate: insert into DEPARTMENT (NAME) values (?)
Hibernate: insert into EMPLOYEE (DESIGNATION, NAME) values (?, ?)
Hibernate: insert into EMPLOYEE (DESIGNATION, NAME) values (?, ?)
Hibernate: insert into EMPLOYEE (DESIGNATION, NAME) values (?, ?)
Hibernate: insert into DEPARTMENT_EMPLOYEE (Department_DPT_ID, employees_EMP_ID) values (?, ?)
Hibernate: insert into DEPARTMENT_EMPLOYEE (Department_DPT_ID, employees_EMP_ID) values (?, ?)
Hibernate: insert into DEPARTMENT_EMPLOYEE (Department_DPT_ID, employees_EMP_ID) values (?, ?)

After executing the MainApp class, you will see the following records in DEPARTMENT, EMPLOYEE and DEPARTMENT_EMPLOYEE tables of MySQL database.

mysql> select * from department;
+--------+---------------+
| DPT_ID | NAME          |
+--------+---------------+
|      1 | IT Department |
+--------+---------------+
1 row in set (0.00 sec)

mysql> select * from employee;
+--------+---------------------+--------+
| EMP_ID | DESIGNATION         | NAME   |
+--------+---------------------+--------+
|      1 | Manager             | Adam   |
|      2 | Software Engineer   | Miller |
|      3 | Associate  Engineer | Smith  |
+--------+---------------------+--------+
3 rows in set (0.00 sec)

mysql> select * from department_employee;
+-------------------+------------------+
| Department_DPT_ID | employees_EMP_ID |
+-------------------+------------------+
|                 1 |                1 |
|                 1 |                2 |
|                 1 |                3 |
+-------------------+------------------+
3 rows in set (0.00 sec)

 

Bidirectional one-to-many association example

Following are the domain model and relational model diagrams of one-to-many bidirectional association.

one-to-many-bi-domain-model.png

one-to-many-bi.png

Entity class

To define a  one-to-many bidirectional association, the @ManyToOne annotation must be used in the target entity (i.e.  Employee entity) and the mappedBy attribute must be used in the source entity (i.e.  Department entity).

Modify the code of Department and Employee classes as follows.

Department.java

package com.boraji.tutorial.hibernate.entity;

import java.util.ArrayList;
import java.util.List;

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

/**
 * @author imssbora
 */
@Entity
@Table(name = "DEPARTMENT")
public class Department {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "DPT_ID")
   private long id;

   @Column(name = "NAME", nullable = false, unique = true)
   private String name;

   @OneToMany(cascade = CascadeType.ALL, mappedBy = "department")
   private List<Employee> employees = new ArrayList<>();

   //Setter and Getter methods
}

Employee.java

package com.boraji.tutorial.hibernate.entity;

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

/**
 * @author imssbora
 */
@Entity
@Table(name = "EMPLOYEE")
public class Employee {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "EMP_ID")
   private long id;

   @Column(name = "NAME", nullable = false)
   private String name;

   @Column(name = "DESIGNATION")
   private String designation;

   @ManyToOne
   @JoinColumn(name = "DPT_ID")
   private Department department;

   //Setter and Getter methods
}

 

Hibernate utility class

No changes are needed in the HibernateUtil class. We can use the same class as used in the one-to-many unidirectional association example.

Main class 

Modify the code of the  MainApp class and run the application.

MainApp.java

package com.boraji.tutorial.hibernate;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.boraji.tutorial.hibernate.entity.Department;
import com.boraji.tutorial.hibernate.entity.Employee;

/**
 * @author imssbora
 */
public class MainApp {
   public static void main(String[] args) {
      Session session = null;
      Transaction transaction = null;
      try {
         session = HibernateUtil.getSessionFactory().openSession();
         transaction = session.beginTransaction();
         transaction.begin();

         Department department = new Department();
         department.setName("IT Department");

         Employee employee1 = new Employee();
         employee1.setName("Adam");
         employee1.setDesignation("Manager");
         employee1.setDepartment(department);

         Employee employee2 = new Employee();
         employee2.setName("Miller");
         employee2.setDesignation("Software Engineer");
         employee2.setDepartment(department);

         Employee employee3 = new Employee();
         employee3.setName("Smith");
         employee3.setDesignation("Associate  Engineer");
         employee3.setDepartment(department);

         department.getEmployees().add(employee1);
         department.getEmployees().add(employee2);
         department.getEmployees().add(employee3);

         session.persist(department);

         transaction.commit();
      } catch (Exception e) {
         if (transaction != null) {
            transaction.rollback();
         }
         e.printStackTrace();
      } finally {
         if (session != null) {
            session.close();
         }
      }

      HibernateUtil.shutdown();
   }
}

Output

Hibernate: create table DEPARTMENT (DPT_ID bigint not null auto_increment, NAME varchar(255) not null, primary key (DPT_ID))
Hibernate: create table EMPLOYEE (EMP_ID bigint not null auto_increment, DESIGNATION varchar(255), NAME varchar(255) not null, DPT_ID bigint, primary key (EMP_ID))
Hibernate: alter table DEPARTMENT drop constraint UK_8ry1iwcodl3ily50pgmc89p4e
Hibernate: alter table DEPARTMENT add constraint UK_8ry1iwcodl3ily50pgmc89p4e unique (NAME)
Hibernate: alter table EMPLOYEE add constraint FKlmn7q9xtxssbqx76bkwukfjb2 foreign key (DPT_ID) references DEPARTMENT (DPT_ID)
Hibernate: insert into DEPARTMENT (NAME) values (?)
Hibernate: insert into EMPLOYEE (DPT_ID, DESIGNATION, NAME) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (DPT_ID, DESIGNATION, NAME) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (DPT_ID, DESIGNATION, NAME) values (?, ?, ?)

After executing the MainApp class, you will see the following records in DEPARTMENT and EMPLOYEE tables of MySQL database.

mysql> select * from department;
+--------+---------------+
| DPT_ID | NAME          |
+--------+---------------+
|      1 | IT Department |
+--------+---------------+
1 row in set (0.00 sec)

mysql> select * from employee;
+--------+---------------------+--------+--------+
| EMP_ID | DESIGNATION         | NAME   | DPT_ID |
+--------+---------------------+--------+--------+
|      1 | Manager             | Adam   |      1 |
|      2 | Software Engineer   | Miller |      1 |
|      3 | Associate  Engineer | Smith  |      1 |
+--------+---------------------+--------+--------+
3 rows in set (0.00 sec)
Download Sources