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.
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.
Download the source code: Hibernate-many-to-many-annotation.zip (8 KB) and import the project in Eclipse. We will update the source code.
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
.
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)
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)
Hibernate-self-reference-annotation.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
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
[code language="java"] List<Employee> list = session.createQuery(" from Employee where employeeId="+2).list();[/code]
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
[code language="java"]
@OneToMany(mappedBy = "manager")
private Set<Employee> subordinates = new HashSet<Employee>();
[/code]
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.
[code language="java"]
manager1.getSubordinates().add(employee1);
manager1.getSubordinates().add(employee2);
session.save(manager1);
[/code]
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?