Hibernate Self Join Annotations One To Many mapping example

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.

self-join-one-to-many

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`)
)

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
}

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>

5. Review Project Structure

hibernate-self-join-one-to-many-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();
    }
}

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

Self Join EMPLOYEE table

self-join-table-output-employee-manager

Download Source Code

Hibernate-self-reference-annotation.zip (8 KB)

Get our Articles via Email. Enter your email address.

You may also like...

15 Comments

  1. Manishkumar Modi says:

    Nice… Very helpfull

  2. v says:

    where’s the setManager method?

    • x says:

      hey , it is the setter method.

  3. baimai says:

    How delete on Hibernate Self Join Annotations One To Many mapping example ?

  4. sandy says:

    nice.

  5. swetha says:

    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.

    • puneetsri81 says:

      just change the cascade type to save &/or update

  6. malay says:

    in the given scenario if i use

    List<Employee> list = session.createQuery(" from Employee where employeeId="+2).list();

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

  7. Vishal Pradhan says:

    Why do we need the

    @OneToMany(mappedBy = &quot;manager&quot;)
    private Set&lt;Employee&gt; subordinates = new HashSet&lt;Employee&gt;();
    

    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?

  8. Mahesh says:

    Nice Article, It saved my time a lot.

  9. Babak says:

    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.

    manager1.getSubordinates().add(employee1);
    manager1.getSubordinates().add(employee2);
    session.save(manager1);
    

    Finally, the result is the same.

  10. RockyH says:

    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?

  11. DIPESH RANE says:

    Very Informative, ROFL on manager’s name and employee referred in example.

  12. Jose Alejandro says:

    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

  13. balu says:

    Some time fetch lazy or eager is not working for fetching the parent record. Can you let me know what is the issue?

Leave a Reply

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