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.
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)
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.
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)
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
.
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.
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)
Once all the source files are in place, the project structure should looks like below:
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.
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.
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)
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)
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)
Hibernate-One-To-Many-Annotation-Set.zip (8 KB)
Hibernate-One-To-Many-Annotation-List.zip (8 KB)
Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…
Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…
Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…
1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…
GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…
1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…
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 =))
Very detailed and simple to understand
yes that's right
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]
This is convience method is it necessary in this senario ?
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,It s nice tutorial.please give this examples using webapplication then it uses
Very useful examples. Please provide some more examples if possible.
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 ??