The Hibernate Many-To-Many Unidirectional Mapping Example tutorial shows you how to use Hibernate Many-To-Many Unidirectional mapping using annotation based configuration. In Many-To-Many relationship, an intermediate table is added and it is known as Joined table. Its primary key is the combination of primary key of both the associated tables.
We are taking an example of Student and ClassRoom relationship. This relationship said that a student can register multiple ClassRoom and one ClassRoom has many students.
Other interesting posts you may like
Let’s begin.
Create required Database Table
We create two tables with these below scripts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
create table CLASS_ROOM ( class_room_id BIGINT NOT NULL AUTO_INCREMENT, name VARCHAR(30) NOT NULL, PRIMARY KEY (CLASS_ROOM_ID) ); create table STUDENT ( id INT(11) NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, entering_date DATE NOT NULL, nationality TEXT NOT NULL, code VARCHAR(30) NOT NULL, class_room_id INT(11) NOT NULL, PRIMARY KEY (id) ); CREATE TABLE STUDENT_CLASS_ROOM ( id INT NOT NULL, class_room_id INT NOT NULL, PRIMARY KEY (id, class_room_id), CONSTRAINT FK_STUDENT FOREIGN KEY (id) REFERENCES STUDENT (id), CONSTRAINT FK_CLASS_ROOM FOREIGN KEY (class_room_id) REFERENCES CLASS_ROOM (class_room_id) ); |
Here we have first created the main tables STUDENT & CLASS_ROOM. then we have created a joined table STUDENT_CLASS_ROOM whose primary key is the combination of primary keys of STUDENT & CLASS_ROOM.
Create project directory structure
In this Hibernate Many-To-Many Unidirectional Mapping Example , we will create java project with final directory structure:
Maven dependencies
We provide the required Hibernate and MySQL dependency in pom.xml like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javabycode.hibernate</groupId> <artifactId>ManyToManyUniDirectionalMapping</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>ManyToManyUniDirectionalMapping</name> <properties> <hibernate.version>4.3.11.Final</hibernate.version> <mysql.version>5.1.31</mysql.version> </properties> <dependencies> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> </dependencies> </project> |
Create Model classes
Model class Student and ClassRoom are simple POJO class. Here we are using class Student and ClassRoom with JPA annotations to map them to a database tables (these tables were created in above step).
Student Model class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
package com.javabycode.hibernate.model; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name = "STUDENT") public class Student implements Serializable { private static final long serialVersionUID = 6832006422622219737L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(name = "NAME", nullable = false) private String name; @Column(name = "ENTERING_DATE", nullable = false) private Date enteringDate; @Column(name = "NATIONALITY", nullable = false) private String nationality; @Column(name = "CODE", nullable = false) private String code; @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name = "STUDENT_CLASS_ROOM", joinColumns = { @JoinColumn(name = "ID") }, inverseJoinColumns = { @JoinColumn(name = "CLASS_ROOM_ID") }) private List<ClassRoom> classRooms = new ArrayList<ClassRoom>(); public Student() { } public Student(String name, Date enteringDate, String nationality, String code) { this.name = name; this.enteringDate = enteringDate; this.nationality = nationality; this.code = code; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setCode(String code) { this.code = code; } public void setEnteringDate(Date enteringDate) { this.enteringDate = enteringDate; } public void setNationality(String nationality) { this.nationality = nationality; } public String getCode() { return code; } public Date getEnteringDate() { return enteringDate; } public String getNationality() { return nationality; } public void setClassRooms(List<ClassRoom> classRooms) { this.classRooms = classRooms; } public List<ClassRoom> getClassRooms() { return classRooms; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (id ^ (id >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Student)) return false; Student other = (Student) obj; if (id != other.id) return false; return true; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", enteringDate=" + enteringDate.toString() + ", nationality=" + nationality + ", code=" + code +", classRooms=" + classRooms + "]"; } } |
ClassRoom Model class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
package com.javabycode.hibernate.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "CLASS_ROOM") public class ClassRoom { @Id @GeneratedValue @Column(name = "CLASS_ROOM_ID") private long id; @Column(name = "NAME") private String name; public ClassRoom() { } public ClassRoom(String name) { this.name = name; } @Column(name = "id") public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (id ^ (id >>> 32)); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof ClassRoom)) return false; ClassRoom other = (ClassRoom) obj; if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { return "ClassRoom [id=" + id + ", name=" + name + "]"; } } |
Let’s dig deeper:
1 2 3 4 5 |
@ManyToMany(cascade = CascadeType.ALL) @JoinTable(name = "STUDENT_CLASS_ROOM", joinColumns = { @JoinColumn(name = "ID") }, inverseJoinColumns = { @JoinColumn(name = "CLASS_ROOM_ID") }) private List<ClassRoom> classRooms = new ArrayList<ClassRoom>(); |
@ManyToMany says that there is a Many-to-Many relationship between Student and ClassRoom. A Student can enjoy multiple ClassRooms, and a ClassRoom can have multiple Students enjoyed.
The attribute cascade = CascadeType.ALL indicates that while persisting (update or delete) Students, ClassRooms will also be persisted (updated or deleted).
@JoinTable indicates that there is a intermediate table which joins two tables: STUDENT and CLASS_ROOM. This table has a primary key that combines by two primary keys of Student and CLASS_ROOM table. This annotation is mainly used on the owning side of the relationship.
The attribute joinColumns refers to the column name of owning side(ID of STUDENT table), and inverseJoinColumns refers to the column of inverse side of relationship(CLASS_ROOM_ID of CLASS_ROOM table).
Note: Don’t forget override hashcode and equals method which are looked by hibernate when holding entities into collections.
Create Hibernate configuration file
We need to provide for hiberate all stuffs like database dialect, driver class, url and account information to connect database. These stuffs is declared in file hibernate.cfg.xml like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.username">javabycode</property> <property name="hibernate.connection.password">mypassword</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/javabycode</property> <property name="show_sql">false</property> <property name="format_sql">false</property> <mapping class="com.javabycode.hibernate.model.Student"/> <mapping class="com.javabycode.hibernate.model.ClassRoom"/> </session-factory> </hibernate-configuration> |
This file is placed in src/main/resources folder.
Create Hibernate Utility class
For configuring hibernate on startup and managing session factory we create the HibernateUtil class like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package com.javabycode.hibernate; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; public class HibernateUtil { private static final SessionFactory sessionFactory; private static final ServiceRegistry serviceRegistry; static { try { Configuration configuration = new Configuration(); configuration.configure(); serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); sessionFactory = new Configuration().configure().buildSessionFactory(serviceRegistry); } catch (Throwable ex) { System.err.println("Session Factory could not be created." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } } |
Create a demo program
We will create main class to demonstrate this Hibernate Many-To-Many Unidirectional Mapping Example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
package com.javabycode.hibernate; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; import org.hibernate.Session; import com.javabycode.hibernate.model.ClassRoom; import com.javabycode.hibernate.model.Student; public class HibernateExample { @SuppressWarnings("unchecked") public static void main(String[] args) { Calendar cal = GregorianCalendar.getInstance(); Student student1 = new Student("David Pham", cal.getTime(), "USA", "1234566"); Student student2 = new Student("Bill Murray", cal.getTime(), "USA", "1234567"); ClassRoom classRoom1 = new ClassRoom("Economics"); ClassRoom classRoom2 = new ClassRoom("Politics"); ClassRoom classRoom3 = new ClassRoom("Maths"); student1.getClassRooms().add(classRoom1); student1.getClassRooms().add(classRoom2); student1.getClassRooms().add(classRoom3); student2.getClassRooms().add(classRoom1); student2.getClassRooms().add(classRoom2); Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); session.persist(student1); session.persist(student2); List<Student> students = (List<Student>) session.createQuery("from Student ").list(); for (Student s : students) { System.out.println("Student : " + s); } List<ClassRoom> classRoomList = (List<ClassRoom>) session.createQuery("from ClassRoom ").list(); for (ClassRoom classRoom : classRoomList) { System.out.println("ClassRoom : " + classRoom); } session.getTransaction().commit(); session.close(); } } |
In the above code, we have initialized the classRooms property of Student class, and just persisted Student objects. Here, ClassRoom objects will be persisted automatically, this operation is thanks to the Cascade attribute.
Run main class and we get the output like below:
1 2 3 4 5 |
Student : Student [id=5, name=David Pham, enteringDate=Sat Oct 08 15:40:37 ICT 2016, nationality=USA, code=1234566, classRooms=[ClassRoom [id=7, name=Economics], ClassRoom [id=8, name=Politics], ClassRoom [id=9, name=Maths]]] Student : Student [id=6, name=Bill Murray, enteringDate=Sat Oct 08 15:40:37 ICT 2016, nationality=USA, code=1234567, classRooms=[ClassRoom [id=7, name=Economics], ClassRoom [id=8, name=Politics]]] ClassRoom : ClassRoom [id=7, name=Economics] ClassRoom : ClassRoom [id=8, name=Politics] ClassRoom : ClassRoom [id=9, name=Maths] |
That’s all on the Hibernate Many-To-Many Unidirectional Mapping Example tutorial.
Download complete source code, please hit link below
ManyToManyUniDirectionalMappingExample.zip (268 downloads)