Hibernate Many-To-One Bidirectional (Annotation)

In this tutorial, we will learn about how to use Hibernate Many-To-One Bidirectional mapping using annotation based configuration.

Schema layout for Many-To-One Bidirectional mapping is exactly same as Many-To-One Unidirectional Mapping. One table has a foreign key column that references the primary key of associated table.In Bidirectional relationship, both side navigation is possible.
ManyToOneBiForeignKeyAssoiciations_img1
We are discussing an example of Student and University relationship. Many student can enroll at one University. And one University can have many students. Let’s get going.


Following technologies being used:

  • Hibernate 4.3.6.Final
  • MySQL Server 5.6
  • Maven 3.1.1
  • JDK 1.6
  • Eclipse JUNO Service Release 2

Let’s begin.

Step 1: Create required Database Table

Open MySQL terminal / workbench terminal and execute following MySQL script :


create table UNIVERSITY (
   university_id BIGINT NOT NULL AUTO_INCREMENT,
   name VARCHAR(30) NOT NULL,
   country  VARCHAR(30) NOT NULL,
   PRIMARY KEY (university_id)
);

create table STUDENT (
   student_id BIGINT NOT NULL AUTO_INCREMENT,
   university_id BIGINT NOT NULL,
   first_name VARCHAR(30) NOT NULL,
   last_name  VARCHAR(30) NOT NULL,
   section    VARCHAR(30) NOT NULL,
   PRIMARY KEY (student_id),
   CONSTRAINT student_university FOREIGN KEY (university_id) REFERENCES UNIVERSITY (university_id) ON UPDATE CASCADE ON DELETE CASCADE
);

Here we have first created University table followed by student table as student table contains a foreign key referring to University table.
Please visit MySQL installation on Local PC in case you are finding difficulties in setting up MySQL locally.

Step 2: Create project directory structure

Following will be the final project structure:

ManyToOneBiForeignKeyAssoiciations_img2

Step 3: Update pom.xml to include required Hibernate and MySQL dependency

Following is the updated minimalistic pom.xml

<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.websystique.hibernate</groupId>
	<artifactId>ManyToOneBiDirectional</artifactId>
	<version>1.0.0</version>
	<packaging>jar</packaging>

	<name>ManyToOneBiDirectional</name>

	<properties>
		<hibernate.version>4.3.6.Final</hibernate.version>
		<mysql.connector.version>5.1.31</mysql.connector.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.connector.version}</version>
		</dependency>
	</dependencies>
	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.2</version>
					<configuration>
						<source>1.6</source>
						<target>1.6</target>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

</project>

On saving pom.xml with above content, Eclipse will download all the dependencies.

Step 4: Create Model classes

Model class Student & University are simple POJO class which is annotated with JPA annotations to map it to a database tables(created in step 1).

package com.websystique.hibernate.model;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "UNIVERSITY")
public class University {

	@Id
	@GeneratedValue
	@Column(name = "UNIVERSITY_ID")
	private long id;

	@Column(name = "NAME")
	private String name;

	@Column(name = "COUNTRY")
	private String country;

	@OneToMany(mappedBy = "university", cascade = CascadeType.ALL)
	private List<Student> students;

	public University() {

	}

	public University(String name, String country) {
		this.name = name;
		this.country = country;
	}

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

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public List<Student> getStudents() {
		return students;
	}

	public void setStudents(List<Student> students) {
		this.students = students;
	}

	@Override
	public String toString() {
		return "University [id=" + id + ", name=" + name + ", country="
				+ country + "]";
	}

}

package com.websystique.hibernate.model;

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.Table;

@Entity
@Table(name = "STUDENT")
public class Student {

	@Id
	@GeneratedValue
	@Column(name = "STUDENT_ID")
	private long id;

	@Column(name = "FIRST_NAME")
	private String firstName;

	@Column(name = "LAST_NAME")
	private String lastName;

	@Column(name = "SECTION")
	private String section;

	@ManyToOne(optional = false)
	@JoinColumn(name = "UNIVERSITY_ID")
	private University university;

	public Student() {
	}

	public Student(String firstName, String lastName, String section) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.section = section;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getSection() {
		return section;
	}

	public void setSection(String section) {
		this.section = section;
	}

	public University getUniversity() {
		return university;
	}

	public void setUniversity(University university) {
		this.university = university;
	}

	@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 + ", firstName=" + firstName + ", lastName="
				+ lastName + ", section=" + section + "]";
	}

}

Interesting things going on here: Look at following code in University class

	@OneToMany(mappedBy = "university", cascade = CascadeType.ALL)
	private List<Student> students;

@OneToMany on list property here denotes that one University can have multiple students.With students property defined in University class, we can now navigate from University to students. mappedBy says that it’s the inverse side of relationship.Also note the cascade attribute, which means the dependent object(Student) will be persisted/updated/deleted automatically on subsequent persist/update/delete on University object.No need to perform operation separately on Student.

On the other hand, we have following in Student

	@ManyToOne(optional = false)
	@JoinColumn(name = "UNIVERSITY_ID")
	private University university;

@JoinColumn says that Student table will contain a separate column UNIVERSITY_ID which will eventually act as a foreign key reference to primary key of University table. @ManyToOne says that multiple Student tuples can refer to same University Tuples(Multiple students can register in same university).Additionally , with optional=false we make sure that no Student tuple can exist without a University tuple.

Step 5: Create Hibernate configuration file

We need to inform hibernate about how to connect to database, which database dialect we will be using so that hibernate can generate the instruction specific to that database.

We define all these information in hibernate.cfg.xml. Create this file with below content and save it in src/main/resources folder.

<?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">myuser</property>
        <property name="hibernate.connection.password">mypassword</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/websystique</property>
        <property name="show_sql">true</property>
        <property name="format_sql">false</property>
        <mapping class="com.websystique.hibernate.model.Student"/>
        <mapping class="com.websystique.hibernate.model.University"/>
    </session-factory>
</hibernate-configuration>

Step 6: Create Hibernate Utility class

This class is well-known in hibernate community, and used for configuring hibernate on startup and managing session factory.

package com.websystique.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtil {
	
	private static final SessionFactory sessionFactory;
	
	static{
		try{
			sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();

		}catch (Throwable ex) {
			System.err.println("Session Factory could not be created." + ex);
			throw new ExceptionInInitializerError(ex);
		}	
	}
	
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	
}

Step 7: Create executable class to Run and perform operations on Database

package com.websystique.hibernate;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Session;

import com.websystique.hibernate.model.Student;
import com.websystique.hibernate.model.University;

public class HibernateStandAlone {

	@SuppressWarnings("unchecked")
	public static void main(String[] args) {

		Student student1 = new Student("Sam", "Disilva", "Maths");
		Student student2 = new Student("Joshua", "Brill", "Science");
		Student student3 = new Student("Peter", "Pan", "Physics");

		University university = new University("CAMBRIDGE", "ENGLAND");
		List<Student> allStudents = new ArrayList<Student>();

		student1.setUniversity(university);
		student2.setUniversity(university);
		student3.setUniversity(university);

		allStudents.add(student1);
		allStudents.add(student2);
		allStudents.add(student3);

		university.setStudents(allStudents);

		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();

		session.persist(university);// Students will be presisted automatically, thanks to CASCADE.ALL defined on students
									// property of University class.

		List<Student> students = (List<Student>) session.createQuery(
				"from Student ").list();
		for (Student s : students) {
			System.out.println("Student Details : " + s);
			System.out.println("Student University Details: "
					+ s.getUniversity());
		}

		// Note that now you can also access the relationship from University to Student

		session.getTransaction().commit();
		session.close();
	}

}

You can see that we have updated both the student and university object with there associations but we have only saved university explicitly.Since we have cascade attribute set to all on student list of University, all child objects(Student) will be saved on persisting parent object(University).

Execute above class as Java application. You will see following output

Hibernate: insert into UNIVERSITY (COUNTRY, NAME) values (?, ?)
Hibernate: insert into STUDENT (FIRST_NAME, LAST_NAME, SECTION, UNIVERSITY_ID) values (?, ?, ?, ?)
Hibernate: insert into STUDENT (FIRST_NAME, LAST_NAME, SECTION, UNIVERSITY_ID) values (?, ?, ?, ?)
Hibernate: insert into STUDENT (FIRST_NAME, LAST_NAME, SECTION, UNIVERSITY_ID) values (?, ?, ?, ?)
Hibernate: select student0_.STUDENT_ID as STUDENT_1_0_, student0_.FIRST_NAME as FIRST_NA2_0_, student0_.LAST_NAME as LAST_NAM3_0_, student0_.SECTION as SECTION4_0_, student0_.UNIVERSITY_ID as UNIVERSI5_0_ from STUDENT student0_
Student Details : Student [id=1, firstName=Sam, lastName=Disilva, section=Maths]
Student University Details: University [id=1, name=CAMBRIDGE, country=ENGLAND]
Student Details : Student [id=2, firstName=Joshua, lastName=Brill, section=Science]
Student University Details: University [id=1, name=CAMBRIDGE, country=ENGLAND]
Student Details : Student [id=3, firstName=Peter, lastName=Pan, section=Physics]
Student University Details: University [id=1, name=CAMBRIDGE, country=ENGLAND]

Below is the snapshot of MySQL database after execution of above program.

ManyToOneBiForeignKeyAssoiciations_img3

ManyToOneBiForeignKeyAssoiciations_img4

That’s it.

Download Source Code


References