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)
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
Hi Sebastian,
That is not ” 1 || 3″, that is “1 && 3”. so both r unique.
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
Really good examples. This got me out of a jam today. Thank you!!
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.
very good way to practise hibernate thanks indeed
Can i make only one Set where will be colleagues and teammates? What the point to have two lists?
How i can get teammates and colleagues in one Set?
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.
Can you please explain the difference between a teammate and a colleague in the example above? I understand everything except for why you declared private Set teammates when you already have private Set colleagues ? They seem to be the exact same thing?
Hello Sir,
I have a doubt.
How to add some more attributes or columns in EMPLOYEE_COLLEAGUE like ‘date’ on which they are connected to eachother.