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 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. 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>
Code language: HTML, XML (xml)

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 }
Code language: Java (java)

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 }
Code language: Java (java)

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; } }
Code language: Java (java)

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>
Code language: HTML, XML (xml)

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>
Code language: HTML, XML (xml)

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

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 }
Code language: Java (java)

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>
Code language: HTML, XML (xml)

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 (?, ?, ?, ?, ?)
Code language: SQL (Structured Query Language) (sql)

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
Code language: SQL (Structured Query Language) (sql)

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 }
Code language: Java (java)

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>
Code language: HTML, XML (xml)

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=?
Code language: SQL (Structured Query Language) (sql)

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 }
Code language: Java (java)

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>
Code language: HTML, XML (xml)

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=?
Code language: SQL (Structured Query Language) (sql)

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)

View Comments

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

  • 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

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

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

  • 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
    [code language="java"]
    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
    [/code]

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

Recent Posts

  • Java

Java URL Encoder/Decoder Example

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

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

5 years ago
  • General

How to Run Local WordPress using Docker

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

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

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

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

5 years ago