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`) )
Code language: SQL (Structured Query Language) (sql)

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 }
Code language: Java (java)

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>
Code language: HTML, XML (xml)

5. Review Project Structure

Review your 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(); } }
Code language: Java (java)

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 (?, ?)
Code language: SQL (Structured Query Language) (sql)

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

Download Source Code

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

View Comments

  • 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

  • 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

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

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

  • 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.
    ?

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

Recent Posts

  • Java

Java URL Encoder/Decoder Example

Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…

4 years ago
  • General

How to Show Multiple Examples in OpenAPI Spec

Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…

4 years ago
  • General

How to Run Local WordPress using Docker

Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…

4 years ago
  • Java

Create and Validate JWT Token in Java using JJWT

1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…

4 years ago
  • Spring Boot

Spring Boot GraphQL Subscription Realtime API

GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…

4 years ago
  • Spring Boot

Spring Boot DynamoDB Integration Test using Testcontainers

1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…

4 years ago