Hibernate One To Many XML Mapping Tutorial

Welcome to the Hibernate Tutorial Series. In previous tutorial we saw how to implement One-to-one Annotation mapping as well as XML mapping. In this tutorial we will understand How to implement Bi-directional One-to-Many relationship in Hibernate using XML mappings.

First let us see the formal definition of One-to-Many relationship:

One-To-Many Relationship: A relationship in which each record in one table is linked to multiple records in another table.

Let us see how to implement One-to-Many relationship in Hibernate using XML mapping.

1. Create Database

For this example, we will MySQL database. Create following two tables in MySQL. Note that Employee and Department table exhibits One-to-many relationship. Each Department can be assosiated 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. Hibernate Maven Dependency

We are using Maven for dependency management. Copy following in the pom.xml.

File: pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>net.viralpatel.hibernate</groupId>
	<artifactId>HibernateHelloWorldXML</artifactId>
	<packaging>jar</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>HibernateHelloWorldXML</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.10</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate</artifactId>
			<version>3.2.6.ga</version>
		</dependency>
	</dependencies>
</project>

3. Hibernate Model Class

Employee and Department model classes are created which maps to the corresponding database tables.

File: Department.java

package net.viralpatel.hibernate;

import java.util.Set;

public class Department {

	private Long departmentId;
	
	private String departmentName;
	
	private Set<Employee> employees;

	// Getter and Setter methods
}

File: Employee.java

package net.viralpatel.hibernate;

import java.sql.Date;

public class Employee {

	private Long employeeId;

	private String firstname;

	private String lastname;

	private Date birthDate;

	private String cellphone;

	private Department department;

	public Employee() {
	}

	public Employee(String firstname, String lastname, Date birthdate,
			String phone) {
		this.firstname = firstname;
		this.lastname = lastname;
		this.birthDate = birthdate;
		this.cellphone = phone;
	}

	// Getter and Setter methods
}

4. Hibernate Utility Class

To access Hibernate API, we will create a wrapper utility class which provides us with SessionFactory.

File: HibernateUtil.java

package net.viralpatel.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

	private static final SessionFactory sessionFactory = buildSessionFactory();

	private static SessionFactory buildSessionFactory() {
		try {
			// Create the SessionFactory from hibernate.cfg.xml
			return new Configuration().configure().buildSessionFactory();
		} catch (Throwable ex) {
			System.err.println("Initial SessionFactory creation failed." + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
}

5. Hibernate Mapping XML (hbm)

Following are the hibernate mapping files for each enitity Employee and Department.

File: Employee.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="net.viralpatel.hibernate">

	<class name="Employee" table="EMPLOYEE">
		<id name="employeeId" column="EMPLOYEE_ID">
			<generator class="native" />
		</id>

		<property name="firstname" />
		<property name="lastname" column="lastname" />
		<property name="birthDate" type="date" column="birth_date" />
		<property name="cellphone" column="cell_phone" />


  		<many-to-one name="department" class="net.viralpatel.hibernate.Department" fetch="select">
            <column name="department_id" not-null="true" />
        </many-to-one>

	</class>
</hibernate-mapping>

File: Department.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="net.viralpatel.hibernate">

    <class name="Department" table="DEPARTMENT">

 		<id name="departmentId" type="java.lang.Long" column="DEPARTMENT_ID" >
			<generator class="native" />
		</id>
		
        <property name="departmentName" column="DEPT_NAME"/>

		<set name="employees" table="employee" 
				inverse="true" lazy="true" fetch="select">
            <key>
                <column name="department_id" not-null="true" />
            </key>
            <one-to-many class="net.viralpatel.hibernate.Employee" />
        </set>
                
	</class>
</hibernate-mapping>

6. Review Project Structure

hibernate-one-to-many-xml-mapping-project-structure

Note that we have used SET to map employees with department. A <set> is similar to except that it can only store unique objects. That means no duplicate elements can be contained in a set. When you add the same element to a set for second time, it will replace the old one. A set is unordered by default but we can ask it to be sorted. The corresponding type of a <set> in Java is java.util.Set.

Execute <set> example

File: Main.java

package net.viralpatel.hibernate;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
 
public class Main {
 
    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", "1212");
        Employee emp2 = new Employee("Tony", "Almeida", "4343");
 
        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 (?, ?, ?, ?, ?)

7. One-to-Many <bag> example

A <bag> is an unordered collection, which can contain duplicated elements. That means if you persist a bag with some order of elements, you cannot expect the same order retains when the collection is retrieved. There is not a “bag” concept in Java collections framework, so we just use a java.util.Listcorrespond to a <bag>.

To implement Bag in our one-to-many mapping example, we will do following changes:

7.1 Update Department Model Class

File: Department.java

package net.viralpatel.hibernate;

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

public class Department {

	private Long departmentId;
	
	private String departmentName;
	
	private List<Employee> employees;

	// Getter and Setter methods

}

7.2 Update XML Mapping

File: Department.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="net.viralpatel.hibernate">

    <class name="Department" table="DEPARTMENT">

 		<id name="departmentId" type="java.lang.Long" column="DEPARTMENT_ID" >
			<generator class="native" />
		</id>
		
        <property name="departmentName" column="DEPT_NAME"/>

	<bag name="employees" table="employee" 
				inverse="true" lazy="true" fetch="select">
            <key>
                <column name="employee_id" not-null="true" />
            </key>
            <one-to-many class="net.viralpatel.hibernate.Employee" />
        </bag>
                
	</class>
</hibernate-mapping>

7.3 Execute <bag> example

Execute the same Main.java file that we created in above example.

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

8. One-to-Many <list> example

A <list> is an indexed collection where the index will also be persisted. That means we can retain the order of the list when it is retrieved. It differs from <bag> for it persists the element Index while a <bag> does not. The corresponding type of a <list> in Java is java.util.List.

To implement List in our one-to-many mapping example, we will do following changes:

8.1 Add Index Column in Employee Table

DROP TABLE if exists `employee`;

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) NOT NULL DEFAULT '0',
	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

Note that in our existing Employee table we added a new column ‘idx’ which stores the index value for each record.

8.2 Update Model Object

File: Department.java

package net.viralpatel.hibernate;

import java.util.List;

public class Department {

	private Long departmentId;
	
	private String departmentName;
	
	private List<Employee> employees;

	// Getter and Setter methods

}

8.3 Update XML Mapping

File: Department.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="net.viralpatel.hibernate">

    <class name="Department" table="DEPARTMENT">

 		<id name="departmentId" type="java.lang.Long" column="DEPARTMENT_ID">
 			<generator class="native" />
 		</id>
		
        <property name="departmentName" column="DEPT_NAME"/>

	<list name="employees" table="employee" 
		inverse="false" cascade="all">

            <key column="department_id"  />
	    <list-index column="idx" />

            <one-to-many class="net.viralpatel.hibernate.Employee" />
        </list>
	</class>
</hibernate-mapping>

In the above hibernate mapping xml file, note that we have added list tag to map a list of employees with department. Also a new index column “idx” is defined which will store the index of records. Note that inverse=”false” is specified in the mapping which makes Department as the relationship owner. Thus when department object is saved, it automatically saves the Employees too. This is required so that Department can manage the index values for employees. The department_id is given as key column.

8.4 Execute <list> example

Output:

Hibernate: insert into DEPARTMENT (DEPT_NAME) values (?)
Hibernate: insert into EMPLOYEE (firstname, lastname, birth_date, cell_phone) values (?, ?, ?, ?)
Hibernate: insert into EMPLOYEE (firstname, lastname, birth_date, cell_phone) 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

9. One-to-Many <array> example

An <array> has the same usage as a <list> except that it corresponds to an Array type in Java and not a java.util.List. It is rarely used unless we are mapping for legacy applications. In most cases, we should use <list> instead. That is because the size of an array cannot be increased or decreased dynamically, where as a list can.

To implement Array in our one-to-many mapping example, we will do following changes:

9.1 Update Model Object

File: Department.java

package net.viralpatel.hibernate;

public class Department {

	private Long departmentId;
	
	private String departmentName;
	
	private Employee[] employees;

	// Getter and Setter methods
}

We simply change the List of Employees to Array of Employee [].

9.2 Update XML Mapping

File: Department.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="net.viralpatel.hibernate">

    <class name="Department" table="DEPARTMENT">

 		<id name="departmentId" type="java.lang.Long" column="DEPARTMENT_ID">
 			<generator class="native" />
 		</id>
		
        <property name="departmentName" column="DEPT_NAME"/>

	<array name="employees" table="employee" 
		inverse="false" cascade="all">
           
           <key column="department_id"  />
	   <list-index column="idx" />
           
           <one-to-many class="net.viralpatel.hibernate.Employee" />
        </array>
    </class>
</hibernate-mapping>

9.2 Execute <array> example

Execute the same Main.java class that we created in above <list> example.

Output:

Hibernate: insert into DEPARTMENT (DEPT_NAME) values (?)
Hibernate: insert into EMPLOYEE (firstname, lastname, birth_date, cell_phone) values (?, ?, ?, ?)
Hibernate: insert into EMPLOYEE (firstname, lastname, birth_date, cell_phone) values (?, ?, ?, ?)
Hibernate: update EMPLOYEE set department_id=?, idx=? where EMPLOYEE_ID=?
Hibernate: update EMPLOYEE set department_id=?, idx=? where EMPLOYEE_ID=?

Download Source Code

Hibernate-one-to-many-set-xml.zip (9 kb)
Hibernate-one-to-many-bag-xml.zip (9 kb)
Hibernate-one-to-many-list-xml.zip (9 kb)
Hibernate-one-to-many-array-xml.zip (9 kb)

Get our Articles via Email. Enter your email address.

You may also like...

18 Comments

  1. farhaan says:

    i want one to many map example. where no cascade option is used.

  2. Jimmy says:

    Ah, so THAT’s how you do Lists in Hibernate! The index is (in retrospect, obviously) important. Thank you very much for this information.

  3. stephen says:

    I am confused about the Key Columns in your source code.

  4. Praveen says:

    confusing can anybody explain it plz

  5. Orlando says:

    Excellent article. Do you have an example how to list the employees of one department?

  6. Nishant Kansal says:

    Really helpful example

  7. Naveen says:

    Just I have a small doubt, like why do we need to mention many-to-one relationship
    does it make any circular reference problem?
    A points B, B points A

  8. Shiju says:

    Exception in thread “main” org.hibernate.PropertyValueException: not-null property references a null or transient value: hib.Employee.department

  9. Lokesh says:

    Thanks ,Helpful tutorial but having doubt why is there circular reference In both the hbm files.?
    How do we delete the child records linked with particular parent. Any help would be appreciated.

  10. ajay mittal says:

    Hi All,

    I am getting following error while saving a list of department first and then employee in the same transaction. kindly help me out

    org.hibernate.exception.ConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`selene7`.`menu_action_id_list`, CONSTRAINT `FK287EF31950855CD3` FOREIGN KEY (`fld_circle_id`, `fld_profile_id`, `element_type`, `action_id`, `element_id`) REFERENCES `action_details` (`fld_ci)
    	at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:74)
    	at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
    	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
    	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
    	at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)
    	at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
    	at com.sun.proxy.$Proxy5.executeUpdate(Unknown Source)
    	at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:56)
    	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3028)
    	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3469)
    	at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:88)
    	at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
    	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
    	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:275)
    	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
    	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
    	at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
    	at com.onmobile.cbc.dstk.client.Demo.saveMultipleObjects(Demo.java:347)
    	at com.onmobile.cbc.dstk.client.Demo.saveChanges(Demo.java:294)
    	at com.onmobile.cbc.dstk.client.Demo.main(Demo.java:391)
    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`selene7`.`menu_action_id_list`, CONSTRAINT `FK287EF31950855CD3` FOREIGN KEY (`fld_circle_id`, `fld_profile_id`, `element_type`, `action_id`, `element_id`) REFERENCES `action_details` (`fld_ci)
    	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    	at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    	at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
    	at com.mysql.jdbc.Util.getInstance(Util.java:381)
    	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1015)
    	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491)
    	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423)
    	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936)
    	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060)
    	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542)
    	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734)
    	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2019)
    	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1937)
    	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1922)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:601)
    	at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
    	... 15 more
    
    • Dinesh says:

      this issue is business services and data service create your application some time are missing parameter name or value that time occuer this error

  11. mangesh pawar says:

    Really very good conceptual example .Everyone able to understand easily.

  12. Nirmal says:

    Hi i am a beginner and i don’t understand why here you are using pom xml.., please kindly revert me back.
    Thank you!!!

  13. Ilir says:

    Excellent article !!!!

  14. Kunal says:

    @ Nirmal “Hi i am a beginner and i don’t understand why here you are using pom xml.., please kindly revert me back.”
    -> Nirmal If you read these in above article it would be clear why is he using pom.xml
    2. Hibernate Maven Dependency
    We are using Maven for dependency management. Copy following in the pom.xml.

    Hence, pom.xml file is used for dependency management. It has nothing to do with if your java project uses hibernate or not.

  15. Anil Nivargi says:

    Thanks good explaination..If anybody wants to know the Interview questions with answers then please go through this blog http://adnjavainterview.blogspot.in/

  16. Pavan Kumar says:

    Hi,
    Iam struck in creating a one to many relation and related hb’s and java objects.
    Probelm: Iam creating that a Lecturer who is belonging to multiple departments .
    i.e Lecturer table should have entries like
    L1 D1
    L1 D2
    L1 D3
    L2 D1
    L2 D3..
    and so on…..
    Can you plz. give me solution for this how you create DB tables, hbm files and also java objects.

    Thanks.

  17. Varun says:

    Hi Viral,
    I am a senior java developer yet for hibernate I always use your blogs for reference. Great job.

Leave a Reply

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