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.
one-to-many-relationship-diagram

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

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


  4.0.0
  HibernateCache
  HibernateCache
  0.0.1-SNAPSHOT
  
  
    
      org.hibernate
      ejb3-persistence
      1.0.1.GA
    
    
      org.hibernate
      hibernate-annotations
      3.3.1.GA
    
    
      mysql
      mysql-connector-java
      5.1.10
    
  

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
}

@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 employees;

	// Getter and Setter methods
}

@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



 

    
        
        com.mysql.jdbc.Driver
        jdbc:mysql://localhost:3306/tutorial
        root
        
        
        1
        org.hibernate.dialect.MySQLDialect
        thread
        org.hibernate.cache.NoCacheProvider
        true
        validate
 
	
	
 		 
    

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

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

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

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

	// Getter and Setter methods
}

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
}	

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());
		department.getEmployees().add(emp1);
		department.getEmployees().add(emp2);
		
		session.save(department);

		session.getTransaction().commit();
		session.close();
	}
}

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=?


one-to-many-list-result


Download Source Code

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



68 Comments

  • suresh 29 May, 2014, 22:38

    Smallestsweetest exaple ine the world love u sir

  • Salim 8 July, 2014, 12:47

    Hi Viral and all,

    can someone please resolve my problem of mapping one to many relationship between a primary key and a composite key.
    http://stackoverflow.com/questions/24609861/hibernate-mapping-one-to-many-relation-ship-between-primary-key-and-composite-ke

  • zeinab 16 July, 2014, 16:28

    ur post saved my day,
    thank u

  • swekha 18 September, 2014, 23:18

    what is the use of mappedby??if we will not specify then what will happen???

    • Siddesh 17 December, 2014, 11:32

      read this:
      http://viralpatel.net/blogs/hibernate-many-to-many-annotation-mapping-tutorial/

      “EMPLOYEE_MEETING” separate table has been created. If we wont specify “mappedBy”, the another table will create with the name MeetingEmployee. But we have already created “EMPLOYEE_MEETING”. To restrict the duplicate table creation, we are telling hibernate to not to create because its already created by “meetings”.

  • ali 10 November, 2014, 2:21

    Hi
    How save foreign key in employee table?
    thanks

  • mi 17 November, 2014, 14:36

    why is it that when you update the non owning entity .. then update the owning entity, the update on the non owning entity will not take effect ??
    is it because of the cascadetypes??
    what would be the appropriate cascade type for this kind of problem??
    should i use merge not update ??
    how ??

  • hgj 28 December, 2014, 14:34

    good article!

  • hgj 28 December, 2014, 14:36

    can any one tell how to the above application in a spring mvc application using hibernate

  • harsh 19 January, 2015, 16:28

    thankssss buddy

  • Nikhil 19 February, 2015, 18:17

    Thanks Viral Nice posts.

  • San 18 March, 2015, 1:18

    Viral, thank you very much for this post! It was just what I wanted!

  • Rakesh Kumar Maharana 5 May, 2015, 15:28

    Hi Viral…
    I have faced a issues while test one-many bi directional mapping .
    please assist what to do.

    Thank you.

    @Entity
    @Table(name=”customers”)
    public class Customer
    {

    // One Customer can place many order
    // One order belongs to one custmer

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name=”cid”)
    int cid;

    @Column(name=”cname”)
    String cname;

    @Column(name=”email”)
    String email;

    @Column(name=”dob”)
    Date dob;

    @Column(name=”phone”)
    Long phone;

    @OneToMany(mappedBy=”customer”)
    Set orders;

    @Entity
    @Table(name=”orders”)
    public class Order {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name=”orderId”)
    int orderId;

    @Column(name=”totalQty”)
    int totalQty;

    @Column(name=”totalCost”)
    Double totalCost;

    @Column(name=”orderDate”)
    Date orderDate;

    @Column(name=”status”)
    String status;

    @JoinColumn(name=”cid”, referencedColumnName=”cid”)
    Customer customer;

    Ecception :
    ———————————

    org.hibernate.MappingException: Could not determine type for: anno.association.mapping.one2many.bidirectional.Customer, for columns: [org.hibernate.mapping.Column(customer)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:266)
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:253)
    at org.hibernate.mapping.Property.isValid(Property.java:185)
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:410)
    at org.hibernate.mapping.RootClass.validate(RootClass.java:192)
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1026)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1211)
    at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:915)
    at anno.association.mapping.one2many.bidirectional.HibernateUtilAnno.(HibernateUtilAnno.java:15)
    at anno.association.mapping.one2many.bidirectional.CMLab27.main(CMLab27.java:19)
    java.lang.NullPointerException
    at anno.association.mapping.one2many.bidirectional.CMLab27.main(CMLab27.java:20)

Leave a Reply

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

Note

To post source code in comment, use [code language] [/code] tag, for example:

  • [code java] Java source code here [/code]
  • [code html] HTML here [/code]