Welcome to the Hibernate Tutorial Series. In previous tutorial we saw how to implement Many to Many relationship using Annotation mapping. In this tutorial we will modify the source code from previous Many To Many XML mapping tutorial and add JPA/Annotation support to it.
Self Join: One to Many
In a query, a table that is related to itself by two different fields. For example, an employee table can include the ID of a manager who is also in the same table.
A Self-Join or Self-Reference is basically one which has some sort of Parent/Child sturcture. We will see an example where we implement Self-Join in class of same type. For example Manager / Subordinates relationship.
Let us see how to implement Self Reference One-to-Many relationship in Hibernate using Annotation.
1. Create Database
For this example, we will MySQL database. We are using Manager / Subordinates relationship as a Self-Join One to Many mapping example. Each manager is an employee. Hence we implement a Parent/Child relationship in Employee enitity.
CREATE TABLE `employee` (
`employee_id` BIGINT(10) NOT NULL AUTO_INCREMENT,
`firstname` VARCHAR(50) NULL DEFAULT NULL,
`lastname` VARCHAR(50) NULL DEFAULT NULL,
`manager_id` BIGINT(20) NULL DEFAULT NULL,
PRIMARY KEY (`employee_id`),
CONSTRAINT `FK_MANAGER` FOREIGN KEY (`manager_id`) REFERENCES `employee` (`employee_id`)
)
Code language: SQL (Structured Query Language) (sql)
Here in Employee table, we defined a column MANAGER_ID which is mapped to the same table’s primary key. Thus for each employee we will store its manager’s id also. Manager will be yet another employee in this table.
2. Project Setup
Download the source code: Hibernate-many-to-many-annotation.zip (8 KB) and import the project in Eclipse. We will update the source code.
3. Update Hibernate Model Class
We will update Employee and Meeting model classes and add Annotations to map them with database table.
File: Employee.java
package net.viralpatel.hibernate;
import java.util.HashSet;
import java.util.Set;
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.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="EMPLOYEE")
public class Employee {
@Id
@Column(name="EMPLOYEE_ID")
@GeneratedValue
private Long employeeId;
@Column(name="FIRSTNAME")
private String firstname;
@Column(name="LASTNAME")
private String lastname;
@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="manager_id")
private Employee manager;
@OneToMany(mappedBy="manager")
private Set<Employee> subordinates = new HashSet<Employee>();
public Employee() {
}
public Employee(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
// Getter and Setter methods
}
Code language: Java (java)
Note that in Employee entity class, we defined two new attributes: Employee manager
and Set<Employee> subordinates
. Attribute manager
is mapped with @ManyToOne
annotation and subordinates
is mapped with @OneToMany
. Also within @OneToMany
attribute we defined mappedBy="manager"
making manager as the relationship owner and thus which manages the foreign relationship within table.
Also the annotation @JoinColumn
is defined on manager making it the relationship owner. @JoinColumn defines the joining column which in our case is manager_id
.
4. Hibernate Configuration File
Edit Hibernate configuration file (hibernate.cfg.xml) and add mappings for Employee and Meeting classes. Following is the final hibernate.cfg.xml 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.Employee"/>
</session-factory>
</hibernate-configuration>
Code language: HTML, XML (xml)
5. Review Project Structure
Execute example
Execute following Main class to test Self Reference relational using Annotation.
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();
Employee manager1 = new Employee("Chuck", "Norris");
Employee employee1 = new Employee("Sergey", "Brin");
Employee employee2 = new Employee("Larry", "Page");
employee1.setManager(manager1);
employee2.setManager(manager1);
session.save(employee1);
session.save(employee2);
session.getTransaction().commit();
session.close();
}
}
Code language: Java (java)
We created one manager “Chuck Norris” and two employees “Sergey Brin” and “Larry Page”. We set the manager details for each employees and saved the employee. Following are the sql statements generated by Hibernate.
Output:
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, manager_id) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, manager_id) values (?, ?, ?)
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, manager_id) values (?, ?, ?)
Code language: SQL (Structured Query Language) (sql)
Self Join EMPLOYEE table
Download Source Code
Hibernate-self-reference-annotation.zip (8 KB)
Nice… Very helpfull
where’s the setManager method?
hey , it is the setter method.
How delete on Hibernate Self Join Annotations One To Many mapping example ?
nice.
Hi , I m facing issue in deletion, when i delete employee it is deleting manager also.. can you tell what could be the issue..\
Thanks in advance.
just change the cascade type to save &/or update
in the given scenario if i use
i get the whole object graph of [Chuck->Sergey,Chuck->Larry] but if i want to load the partial object graph & work on that only [Chuck->Sergey] then what needs to be done ? (I don’t want Larry to be present in the whole relation i have fetched)..
Why do we need the
As we are not using this anywhere in main method as well, the code is running as it required if we remove this code.
So, what is the use and meaning of using these statements in this example?
Nice Article, It saved my time a lot.
Great article!
But it doesn’t work this way for me.
I have to add the employees to the manager and then persist the manager will write the 3 lines in the db.
Finally, the result is the same.
I am newbie so my question might be silly,
You haven’t saved the Manager before saving Employee.
Does it save the manager while first employee is saved?
Very Informative, ROFL on manager’s name and employee referred in example.
I implemented this but i have a problem. Imagine you have like 5 levels of hierarchy. Employer 1-> Employer 2-> Employer 3-> Employer 4-> Employee. If i want to get all the employees..this would get me many instances of the same object. For example:
Employee. Parent = Employer 4 . Parent = Employer 3. Parent= Employer 2. Parent = Employer 1.Parent = NULL
Employer 4 . Parent = Employer 3. Parent= Employer 2. Parent = Employer 1.Parent = NULL
Employer 3. Parent= Employer 2. Parent = Employer 1.Parent = NULL
Employer 2. Parent = Employer 1..Parent = NULL
Employer 1.
I would like to limit this to only give me the instance of the direct employer. Is there anyway to do that? To get a result like this:
Employee. Parent = Employer 4 .Parent = NULL
Employer 4 . Parent = Employer 3. Parent= NULL
Employer 3. Parent= Employer 2. Parent = NULL
Employer 2. Parent = Employer 1.Parent = NULL
Hi…I have also come across the same situation. Can you please tell me how you applied mappings in entity, in the above scenario.
Some time fetch lazy or eager is not working for fetching the parent record. Can you let me know what is the issue?
which tool u have used for schema design. which u have show in your example.i mean (image)
Legend! You made my life very easy. Thank you :)
How should I make the save employee endpoint work in the controller level?
hi
This mapping is tricky I have a similar parent / children relationship for a CATEGORY structure
And if I select the top category (1)
it loops along the 2nd child and it’s parent
“uid”: 1,
“name”: “DOMAIN”,
“title”: “DOMAIN”,
“type”: “DOMAIN”,
“children”: [
{
“uid”: 2,
“name”: “LINE”,
“title”: “LINE”,
“type”: “LINE”,
“children”: [
{
“uid”: 6,
“name”: “PORTFOLIO”,
“title”: “PORTFOLIO”,
“type”: “PORTFOLIO”,
“children”: [ ],
“parent”: {
“uid”: 2,
“name”: “LINE”,
“title”: “LINE”,
“type”: “LINE”,
“children”: [
{
“uid”: 6,
“name”: “PORTFOLIO”,
“title”: “PORTFOLIO”,
“type”: “PORTFOLIO”,
“children”: [ ],
“parent”: {
“uid”: 2,
“name”: “LINE”,
“title”: “LINE”,
“type”: “LINE”,
“children”: [……………………