Hibernate Self Join Many To Many Annotations mapping example

Welcome to the Hibernate Tutorial Series. In previous tutorial we saw how to implement Self Reference One to Many relationship using Annotation mapping. In this tutorial we will modify the source code from previous tutorial and implement Self-Join Many to Many mapping using Annotation..

Self Join: Many to Many
In a query, a table that is related to itself by a connecting / bridge table. For example, an employee table defining a relationship Employee-Colleague where colleague is yet another employee. The relationship is mapped by another bridge table called Employee_Colleague table.

Let us see how to implement Self Reference Many-to-Many relationship in Hibernate using Annotation.

1. Create Database

For this example we will MySQL database. We are using Employee / Colleagues relationship as a Self-Join Many to Many mapping example.

CREATE TABLE `employee` (
	`employee_id` BIGINT(10) NOT NULL AUTO_INCREMENT,
	`firstname` VARCHAR(50) NULL DEFAULT NULL,
	`lastname` VARCHAR(50) NULL DEFAULT NULL,
	PRIMARY KEY (`employee_id`)
)


CREATE TABLE `employee_colleague` (
	`employee_id` BIGINT(20) NOT NULL,
	`colleague_id` BIGINT(20) NOT NULL,
	PRIMARY KEY (`employee_id`, `colleague_id`),
	CONSTRAINT `FK_EMP` FOREIGN KEY (`employee_id`) REFERENCES `employee` (`employee_id`),
	CONSTRAINT `FK_COL` FOREIGN KEY (`colleague_id`) REFERENCES `employee` (`employee_id`)
)

Employee table stores information about each employee.The Employee-Colleague relationship is stored in EMPLOYEE_COLLEAGUE table. Both employee_id and colleague_id from EMPLOYEE_COLLEAGUE table is mapped to employee_id of EMPLOYEE table.

2. Project Setup

Download the source code: Hibernate-self-reference-annotation.zip (8 KB) and import the project in Eclipse. We will update the source code.

3. Hibernate Model Class

We will update Employee model class and add Self Referencing Many to Many relationship.

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.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.JoinColumn;

@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;
	

	@ManyToMany(cascade={CascadeType.ALL})
	@JoinTable(name="EMPLOYEE_COLLEAGUE",
		joinColumns={@JoinColumn(name="EMPLOYEE_ID")},
		inverseJoinColumns={@JoinColumn(name="COLLEAGUE_ID")})
	private Set<Employee> colleagues = new HashSet<Employee>();

	@ManyToMany(mappedBy="colleagues")
	private Set<Employee> teammates = new HashSet<Employee>();

	public Employee() {
	}

	public Employee(String firstname, String lastname) {
		this.firstname = firstname;
		this.lastname = lastname;
	}
		
	// Getter and Setter methods
}

Note that we have defined two attributes Set<Employee> colleagues and Set<Employee> teammates. Also the attribute colleagues is relationship owner here. This is because we have marked colleagues attribute with @JoinTable annotation and teammates attribute with mappedBy="colleagues".

Also note that the relationship is defined within table EMPLOYEE_COLLEAGUE which we marked using @JoinTable annotation.

@ManyToMany annotation is defined on both colleagues and teammates attributes.

4. Hibernate Configuration File

Edit Hibernate configuration file (hibernate.cfg.xml) and add mappings for Employee class. 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

Review your project structure.
hibernate-self-join-many-to-many-project-structure

Execute example

Execute following Main class to test Self Reference relational using Annotation. Here we create four employee objects and map few of them as colleagues of one another.

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 employee1 = new Employee("Sergey", "Brin");
        Employee employee2 = new Employee("Larry", "Page");
        Employee employee3 = new Employee("Marrisa", "Mayer");
        Employee employee4 = new Employee("Matt", "Cutts");

        employee1.getColleagues().add(employee3);
        employee1.getColleagues().add(employee4);
        employee2.getColleagues().add(employee4);
        employee3.getColleagues().add(employee4);
        employee4.getColleagues().add(employee1);
        employee4.getColleagues().add(employee3);
        

        session.save(employee1);
        session.save(employee2);
        session.save(employee3);
        session.save(employee4);
        
        session.getTransaction().commit();
        session.close();
    }
}

Output:

Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME) values (?, ?)
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME) values (?, ?)
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME) values (?, ?)
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME) values (?, ?)
Hibernate: insert into EMPLOYEE_COLLEAGUE (EMPLOYEE_ID, COLLEAGUE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_COLLEAGUE (EMPLOYEE_ID, COLLEAGUE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_COLLEAGUE (EMPLOYEE_ID, COLLEAGUE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_COLLEAGUE (EMPLOYEE_ID, COLLEAGUE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_COLLEAGUE (EMPLOYEE_ID, COLLEAGUE_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_COLLEAGUE (EMPLOYEE_ID, COLLEAGUE_ID) values (?, ?)

Once we execute above Main class, the employee details are saved with their relationship. Query both EMPLOYEE and EMPLOYEE_COLLEAGUE tables are see the output.

Self Join Many-To-Many table output

self-join-many-to-many-table-output

Download Source Code

Hibernate-self-join-many-to-many-annotation.zip (8 KB)

Get our Articles via Email. Enter your email address.

You may also like...

10 Comments

  1. Sebastian says:

    Hi!!! this was very helpful, but I have a question… in this example, in the EMPLOYEE_COLLEAGUE table, is the | 1 || 3 | record and the | 3 || 1 | record… there is any way to create only one record but the 2 employees sees each other???

    thanks

  2. S.K.Sahu says:

    Hi Sebastian,
    That is not ” 1 || 3″, that is “1 && 3”. so both r unique.

    thanks

  3. Andrew says:

    Hello!

    Excellent guides. These have been invaluable to me. I cannot thank you enough.
    I was wondering however, would it be possible to define the kind of self join relationship created?

    For example employees Bob and Fred are ‘happy’ colleagues whilst Alice and Tom are ‘unhappy’ colleagues?

    All the very best,
    Andrew

  4. Doug says:

    Really good examples. This got me out of a jam today. Thank you!!

  5. vivek says:

    In the man class on line
    employee1.getColleagues().add(employee3);
    employee1.getColleagues().add(employee4);

    A null Pointer exception will occur. I have tested it as well.

  6. Udit Agarwal says:

    very good way to practise hibernate thanks indeed

  7. Artur says:

    Can i make only one Set where will be colleagues and teammates? What the point to have two lists?

  8. Artur says:

    How i can get teammates and colleagues in one Set?

  9. Satish says:

    Hi Viral
    This is one issues we are facing when we try to get object of Employee entity and getting getColleagues then that time all coressponding recods automatically deleted why this heppening.
    ?

  10. Matheus says:

    Hi, i am learning about springboot and i have a scenario like that in this tutorial – a user table and a userfollow table with iduser and iduserfollow fields both are foreign Keys with table user.

    in my test applycation i´m using spring data jpa and my classes are extending JPARepository, my problem is:
    when i call repository.findAll method seens like the application enters a loop in the manytomany relationship. i have only two record in the users table but the result of the query is very much then this.

    Any idea in how can i solve this problem?
    Maybe is this a bug/problem in the spring-boot framework?

    Thanks.

Leave a Reply

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