Hibernate One To Many Annotation tutorial

Welcome to the Hibernate Tutorial Series. In previous tutorial we saw how to implement One to Many relationship using XML mapping. In this tutorial we will modify the source code from previous One To Many XML mapping tutorial and add JPA/Annotation support to it.

1. Database Setup

For this example, we will use MySQL database. Create following two tables in MySQL. Note that Employee and Department table exhibits One-to-many relationship. Each Department can be associated with multiple Employees and each Employee can have only one Department.

CREATE TABLE `department` ( `department_id` BIGINT(20) NOT NULL AUTO_INCREMENT, `dept_name` VARCHAR(50) NOT NULL DEFAULT '0', PRIMARY KEY (`department_id`) ) COLLATE='latin1_swedish_ci' ENGINE=InnoDB ROW_FORMAT=DEFAULT AUTO_INCREMENT=115 CREATE TABLE `employee` ( `employee_id` BIGINT(10) NOT NULL AUTO_INCREMENT, `firstname` VARCHAR(50) NULL DEFAULT NULL, `lastname` VARCHAR(50) NULL DEFAULT NULL, `birth_date` DATE NULL DEFAULT NULL, `cell_phone` VARCHAR(15) NULL DEFAULT NULL, `department_id` BIGINT(20) NULL DEFAULT NULL, PRIMARY KEY (`employee_id`), INDEX `FK_DEPT` (`department_id`), CONSTRAINT `FK_DEPT` FOREIGN KEY (`department_id`) REFERENCES `department` (`department_id`) ) COLLATE='latin1_swedish_ci' ENGINE=InnoDB ROW_FORMAT=DEFAULT
Code language: SQL (Structured Query Language) (sql)

2. Project Setup

Download the source code: Hibernate-one-to-many-set-example.zip (9 KB) and import the project in Eclipse. We will update the source code.

3. Update Maven Dependency

File: pom.xml

<?xml version="1.0" encoding="UTF-8"?><project> <modelVersion>4.0.0</modelVersion> <groupId>HibernateCache</groupId> <artifactId>HibernateCache</artifactId> <version>0.0.1-SNAPSHOT</version> <description></description> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>ejb3-persistence</artifactId> <version>1.0.1.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.1.GA</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> </dependency> </dependencies> </project>
Code language: HTML, XML (xml)

3. Remove Hibernate Mapping (hbm) Files

We are not going to use hibernate mapping files or hbm files as we will map the model using Java 5 Annotations. Delete the files employee.hbm.xml and department.hbm.xml.

4. Update Hibernate Model Class

File: Employee.java

package net.viralpatel.hibernate; import java.sql.Date; 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="EMPLOYEE") public class Employee { @Id @GeneratedValue @Column(name="employee_id") private Long employeeId; @Column(name="firstname") private String firstname; @Column(name="lastname") private String lastname; @Column(name="birth_date") private Date birthDate; @Column(name="cell_phone") private String cellphone; @ManyToOne @JoinColumn(name="department_id") private Department department; public Employee() { } public Employee(String firstname, String lastname, String phone) { this.firstname = firstname; this.lastname = lastname; this.birthDate = new Date(System.currentTimeMillis()); this.cellphone = phone; } // Getter and Setter methods }
Code language: Java (java)

@ManyToOne annotation defines a single-valued association to another entity class that has many-to-one multiplicity. It is not normally necessary to specify the target entity explicitly since it can usually be inferred from the type of the object being referenced.

@JoinColumn is used to specify a mapped column for joining an entity association.

File: Department.java

package net.viralpatel.hibernate; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name="DEPARTMENT") public class Department { @Id @GeneratedValue @Column(name="DEPARTMENT_ID") private Long departmentId; @Column(name="DEPT_NAME") private String departmentName; @OneToMany(mappedBy="department") private Set<Employee> employees; // Getter and Setter methods }
Code language: Java (java)

@OneToMany annotation defines a many-valued association with one-to-many multiplicity.
If the collection is defined using generics to specify the element type, the associated target entity type need not be specified; otherwise the target entity class must be specified.

The association may be bidirectional. 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. In our case, this is passport. As you can see, you don’t have to (must not) declare the join column since it has already been declared on the owners side.

5. Update Hibernate Configuration File

File: hibernate.cfg.xml

<?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> <!-- Database connection settings --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/tutorial</property> <property name="connection.username">root</property> <property name="connection.password"></property> <property name="connection.pool_size">1</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="current_session_context_class">thread</property> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">validate</property> <mapping class="net.viralpatel.hibernate.Department"/> <mapping class="net.viralpatel.hibernate.Employee"/> </session-factory> </hibernate-configuration>
Code language: HTML, XML (xml)

6. Review Project Structure

Once all the source files are in place, the project structure should looks like below:

7. Execute example

Execute following Main.java file which will create one Department and two Employees.

File: Main.java

package net.viralpatel.hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory; public class Main { @SuppressWarnings("unchecked") public static void main(String[] args) { SessionFactory sf = HibernateUtil.getSessionFactory(); Session session = sf.openSession(); session.beginTransaction(); Department department = new Department(); department.setDepartmentName("Sales"); session.save(department); Employee emp1 = new Employee("Nina", "Mayers", "111"); Employee emp2 = new Employee("Tony", "Almeida", "222"); emp1.setDepartment(department); emp2.setDepartment(department); session.save(emp1); session.save(emp2); session.getTransaction().commit(); session.close(); } }
Code language: Java (java)

Output:

Hibernate: insert into DEPARTMENT (DEPT_NAME) values (?) Hibernate: insert into EMPLOYEE (firstname, lastname, birth_date, cell_phone, department_id) values (?, ?, ?, ?, ?) Hibernate: insert into EMPLOYEE (firstname, lastname, birth_date, cell_phone, department_id) values (?, ?, ?, ?, ?)
Code language: SQL (Structured Query Language) (sql)

Thus we saw in above example how to implement One to Many relationship in Hibernate using Annotation. Also we used java.util.Set for our example.

8. One- To Many Bi-directional Indexed mapping

Above example was pretty straightforward. We mapped multiple employees with a department. For this we used java.lang.Set. But the order in which the employees are mapped with department is not conserved. What if you have a requirement where you want to preserve order for entities that you save.

We can use java.util.List to map ordered entities. For this first we will need to add a column IDX in Employee table which will store the index value.

8.1 Modify Employee table

CREATE TABLE `employee` ( `employee_id` BIGINT(10) NOT NULL AUTO_INCREMENT, `firstname` VARCHAR(50) NULL DEFAULT NULL, `lastname` VARCHAR(50) NULL DEFAULT NULL, `birth_date` DATE NULL DEFAULT NULL, `cell_phone` VARCHAR(15) NULL DEFAULT NULL, `department_id` BIGINT(20) NULL DEFAULT NULL, `idx` INT(11) NULL DEFAULT NULL, PRIMARY KEY (`employee_id`), INDEX `FK_DEPT` (`department_id`), CONSTRAINT `FK_DEPT` FOREIGN KEY (`department_id`) REFERENCES `department` (`department_id`) ) COLLATE='latin1_swedish_ci' ENGINE=InnoDB ROW_FORMAT=DEFAULT AUTO_INCREMENT=33
Code language: SQL (Structured Query Language) (sql)

8.2 Modify Hibernate Model classes

Update Employee.java and Department.java model classes and add the list support. Also note that we are changing the annotations.

File: Department.java

package net.viralpatel.hibernate; import java.util.List; 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.OneToMany; import javax.persistence.Table; import org.hibernate.annotations.IndexColumn; @Entity @Table(name="DEPARTMENT") public class Department { @Id @GeneratedValue @Column(name="DEPARTMENT_ID") private Long departmentId; @Column(name="DEPT_NAME") private String departmentName; @OneToMany(cascade={CascadeType.ALL}) @JoinColumn(name="department_id") @IndexColumn(name="idx") private List<Employee> employees; // Getter and Setter methods }
Code language: Java (java)

Note that in Department entity class, we removed mappedBy clause from @OneToMany. This mark Department as the relationship owner and make it responsible to update foriegn keys and index values.

Also we specified index coulmn using @IndexColumn annotation to specify which column in Employee table we would like to store index in.

File: Employee.java

package net.viralpatel.hibernate; import java.sql.Date; 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="EMPLOYEE") public class Employee { @Id @GeneratedValue @Column(name="employee_id") private Long employeeId; @Column(name="firstname") private String firstname; @Column(name="lastname") private String lastname; @Column(name="birth_date") private Date birthDate; @Column(name="cell_phone") private String cellphone; @ManyToOne @JoinColumn(name="department_id", insertable=false, updatable=false, nullable=false) private Department department; public Employee() { } public Employee(String firstname, String lastname, String phone) { this.firstname = firstname; this.lastname = lastname; this.birthDate = new Date(System.currentTimeMillis()); this.cellphone = phone; } // Getter and Setter methods }
Code language: Java (java)

8.3 Execute List example

File: Department.java

package net.viralpatel.hibernate; import java.util.ArrayList; import org.hibernate.Session; import org.hibernate.SessionFactory; public class Main { @SuppressWarnings("unchecked") public static void main(String[] args) { SessionFactory sf = HibernateUtil.getSessionFactory(); Session session = sf.openSession(); session.beginTransaction(); Department department = new Department(); department.setDepartmentName("Sales"); Employee emp1 = new Employee("Nina", "Mayers", "111"); Employee emp2 = new Employee("Tony", "Almeida", "222"); department.setEmployees(new ArrayList<Employee>()); department.getEmployees().add(emp1); department.getEmployees().add(emp2); session.save(department); session.getTransaction().commit(); session.close(); } }
Code language: Java (java)

Output:

Hibernate: insert into DEPARTMENT (DEPT_NAME) values (?) Hibernate: insert into EMPLOYEE (birth_date, cell_phone, firstname, lastname) values (?, ?, ?, ?) Hibernate: insert into EMPLOYEE (birth_date, cell_phone, firstname, lastname) values (?, ?, ?, ?) Hibernate: update EMPLOYEE set department_id=?, idx=? where employee_id=? Hibernate: update EMPLOYEE set department_id=?, idx=? where employee_id=?
Code language: SQL (Structured Query Language) (sql)

Download Source Code

Hibernate-One-To-Many-Annotation-Set.zip (8 KB)
Hibernate-One-To-Many-Annotation-List.zip (8 KB)

View Comments

  • Just landed on your tutorials and they look very detailed interesting ...
    Will start following them in the next days (weeks) ... thank you for your efforts =))

  • Please share the Department.setEmployees() method. Without that, I don't see a way for an Employee to know what to which Department it belongs. I'm assuming that the method will look like this:
    [code language="java"]
    public void setEmployees(Set employees) {
    for( Employee e : employees ) {
    e.setDepartment(this);
    this.employee = e;
    }
    }
    [/code]

  • Hi Viral,

    First of all, Thanks for detail tutorial. Can you please add samples to retrieve information from DB with varoius cases one-one, one-many, Many-one.

    Thanks

  • Plz some one tell me How i use one to many mapping in hibernate for creation of three tables.
    1.discussion(discId,queId,ansId)
    2.question(queId,question,postdate)
    3.answer(ansId,answer,postDate)

    Thanks in advance

    Plz rply its argent

  • when using this code in dynamic project of struts2 i get following error..
    :-
    Could not determine type for: java.util.Set, at table: UserDetails, for columns: [org.hibernate.mapping.Column(questionSet)]

    • Hi Mandar,
      Are you using field access strategy for annotating your entity properties? i.e. Are you adding annotations on class fields or to getter methods?
      [code language="java"]
      //Field access strategy
      @Id
      private String id;

      //Property access strategy
      @Id
      public String getId();
      [/code]

      Check if you using only one access strategy and not mixing up both.

  • HI,

    The example are very help full for learning new technology in java.I m following and it is very understanding .I need front end design of screen with back end data using GWT .It is my humble request to send me tutorial of gwt using hibernate frame work

    • Thanks Vinayak. I have not written tutorial on GWT with Hibernate, but I hope to write soon. Please subscribe for articles via email so you don't miss any future tutorials.

  • Hi Viral, Thanks for detailed explanation....Can we do this mapping with a single entity class using @SecondaryTable.
    (NOTE: I need both primary keys to be inserted using the single entity class itself )

  • department_employee table is also generated without any data please explain this and why the content is null ??

Recent Posts

  • Java

Java URL Encoder/Decoder Example

Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…

4 years ago
  • General

How to Show Multiple Examples in OpenAPI Spec

Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…

4 years ago
  • General

How to Run Local WordPress using Docker

Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…

4 years ago
  • Java

Create and Validate JWT Token in Java using JJWT

1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…

4 years ago
  • Spring Boot

Spring Boot GraphQL Subscription Realtime API

GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…

4 years ago
  • Spring Boot

Spring Boot DynamoDB Integration Test using Testcontainers

1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…

4 years ago