One to Many Mapping in JPA

In this example I am going to show you how we can implement One to Many(@OneToMany) relationship using JPA persistence API in Java.

The Java Persistence API (JPA) is a Java specification for accessing, persisting, and managing data between Java objects / classes and a relational database.

The JPA is used to reduce the burden of writing codes for relational object management, a programmer or developer follows the ‘JPA Provider’ framework, which allows easy interaction with database instance. The JPA being a Java framework a programmer also needs not to worry about the SQL part of the code, he/she may need to hardly concentrate on SQL coding.

You may be interested in Many to One Mapping in JPA , Many to Many Mapping in JPA and One to One Mapping in JPA

In this One to Many mapping example, we have Teacher and Period relationship. A class period can be taken by multiple teachers at different times.

For this tutorial we will create a standalone maven project in Eclipse. If you already have an idea on how to create a maven project in Eclipse will be great otherwise I will tell you here how to create a maven project in Eclipse.

Prerequisites
The following configurations are required in order to run the application
Eclipse Mars
JDK 1.8
Have maven installed and configured
JPA dependencies in pom.xml
Now we will see the below steps how to create a maven based spring project in Eclipse.
Step 1. Create a standalone maven project in Eclipse

Go to File -> New -> Other. On popup window under Maven select Maven Project. Then click on Next. Select the workspace location – either default or browse the location. Click on Next. Now in next window select the row as highlighted from the below list of archtypes and click on Next button.

maven-arctype-quickstart
Now enter the required fields (Group Id, Artifact Id) as shown below
Group Id : com.roytuts
Artifact Id : jpa
Step 2. Modify the pom.xml file as shown below.

<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.roytuts</groupId>
	<artifactId>jpa</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>jpa</name>
	<url>http://maven.apache.org</url>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
		<hibernate.version>4.3.10.Final</hibernate.version>
		<mysqlconnector.version>5.1.34</mysqlconnector.version>
	</properties>
	<dependencies>
		<!-- JPA -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<!-- mysql java connector -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysqlconnector.version}</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>${java.version}</source>
					<target>${java.version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Step 3. If you see JRE System Library[J2SE-1.5] then change the version by below process

Do right-click on the project and go to Build -> Configure build path, under Libraries tab click on JRE System Library[J2SE-1.5], click on Edit button and select the appropriate jdk 1.8 from the next window. Click on Finish then Ok.

Step 4. Create src/main/resources folder for putting the resource files.

Do right-click on the project and go New -> Source Folder. Give Folder name: as src/main/resources and click on Finish button.

Then create META-INF folder under src/main/resources source directory.

Step 5. Create an XML file persistence.xml under src/main/resources/META-INF.

Do right-click on META-INF in the project and go New -> file. Give File name: as persistence.xml and click on Finish button.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
	version="2.1">
	<persistence-unit name="userPersistanceUnit"
		transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
		<class>com.roytuts.jpa.entity.Teacher</class>
		<class>com.roytuts.jpa.entity.Period</class>
		<properties>
			<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
			<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/roytuts" />
			<property name="javax.persistence.jdbc.user" value="root" />
			<property name="javax.persistence.jdbc.password" value="" />
			<property name="dialect" value="org.hibernate.dialect.MySQLDialect" />
			<property name="hibernate.transaction.flush_before_completion"
				value="true" />
			<property name="hibernate.show_sql" value="true" />
			<property name="hibernate.format_sql" value="true" />
		</properties>
	</persistence-unit>
</persistence>

In the above XML file, we have transaction-type as RESOURCE_LOCAL. There are two types of Transaction management types supported in JPA.

RESOURCE LOCAL Transactions
JTA or GLOBAL Transactions

Resource local transactions refer to the native transactions of the JDBC Driver whereas JTA transactions refer to the transactions of the JEE server. A Resource Local transaction involves a single transactional resource, for example a JDBC Connection. Whenever you need two or more resources( for example a JMS Connection and a JDBC Connection )  within a single transaction, you use  JTA Transaction. Container Managed Entity Managers always use JTA transactions as the container takes care of transaction life cycle management and spawning the transaction across multiple transactional resources. Application Managed Entity Managers can use either Resource Local Transactions or JTA transactions.

Normally in JTA or global transaction, a third party transaction monitor enlists the different transactional resources within a transaction, prepares them for a commit and finally commits the transaction. This process of first preparing the resources for transaction(by doing a dry run) and then committing(or rolling back) is called a 2 phase commit.

Step 6. Create Period.java class under src/main/java folder

package com.roytuts.jpa.entity;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "period")
public class Period {
	@Id
	@Column(name = "id")
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	@Column(name = "period")
	private String period;
	@OneToMany(targetEntity = Teacher.class)
	private List<Teacher> teachers;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getPeriod() {
		return period;
	}
	public void setPeriod(String period) {
		this.period = period;
	}
	public List<Teacher> getTeachers() {
		return teachers;
	}
	public void setTeachers(List<Teacher> teachers) {
		this.teachers = teachers;
	}
}

In the above class we have @OneToMany annotation which means a period can be taken by multiple teachers at different times or on different days.

Step 8. Create Teacher.java class under src/main/java folder

package com.roytuts.jpa.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "teacher")
public class Teacher {
	@Id
	@Column(name = "id")
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	@Column(name = "name")
	private String name;
	@Column(name = "expertise")
	private String expertise;
	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 String getExpertise() {
		return expertise;
	}
	public void setExpertise(String expertise) {
		this.expertise = expertise;
	}
}

Step 9. Create below custom exception class JpaException under src/main/java folder

package com.roytuts.jpa.exception;
public class JpaException extends RuntimeException {
	private static final long serialVersionUID = 1L;
	public JpaException(String msg) {
		super(msg);
	}
	public JpaException(Throwable t) {
		super(t);
	}
	public JpaException(String msg, Throwable t) {
		super(msg, t);
	}
}

Step 10. Now create an enum PersistenceManager for creating EntityManagerFactory and EntityManager

package com.roytuts.jpa.manager;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public enum PersistenceManager {
	_INSTANCE;
	private EntityManagerFactory emf;
	private PersistenceManager() {
		emf = Persistence.createEntityManagerFactory("userPersistanceUnit");
	}
	public EntityManager getEntityManager() {
		return emf.createEntityManager();
	}
	public void close() {
		emf.close();
	}
}

Step 11. Create a main class which will test One to Many(@OneToMany) strategy.

package com.roytuts.jpa.relation.test;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import com.roytuts.jpa.entity.Period;
import com.roytuts.jpa.entity.Teacher;
import com.roytuts.jpa.exception.JpaException;
import com.roytuts.jpa.manager.PersistenceManager;
public class JpaRelationshipTest {
	public static void main(String[] args) {
		EntityManager em = PersistenceManager._INSTANCE.getEntityManager();
		try {
			em.getTransaction().begin();
			Period period = new Period();
			Teacher teacher1 = new Teacher();
			Teacher teacher2 = new Teacher();
			teacher1.setName("BCD");
			teacher1.setExpertise("Statistics");
			teacher2.setName("UKR");
			teacher2.setExpertise("System Programming");
			em.persist(teacher1);
			em.persist(teacher2);
			List<Teacher> teachers = new ArrayList<>();
			teachers.add(teacher1);
			teachers.add(teacher2);
			period.setPeriod("Java");
			period.setTeachers(teachers);
			em.persist(period);
			em.getTransaction().commit();
		} catch (JpaException e) {
			em.getTransaction().rollback();
			e.printStackTrace();
		} finally {
			em.close();
			PersistenceManager._INSTANCE.close();
		}
	}
}

Step 12. Create tables in MySQL database

period table

USE `roytuts`;
/*Table structure for table `period` */
DROP TABLE IF EXISTS `period`;
CREATE TABLE `period` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `period` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

teacher table

USE `roytuts`;
/*Table structure for table `teacher` */
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `expertise` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

period_teacher table

USE `roytuts`;
/*Table structure for table `period_teacher` */
DROP TABLE IF EXISTS `period_teacher`;
CREATE TABLE `period_teacher` (
  `period_id` int(10) unsigned NOT NULL,
  `teachers_id` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

See in the above period_teacher table how period table’s id(<table name>_<table’s id field name> i.e., period_id) and teacher’s table id(<table name>_<table’s id field name> i.e., teacher_id) are declared to keep relationship among two tables.

Step 13. Run the above main class, you will see below output in the console.

Hibernate:
    insert
    into
        teacher
        (expertise, name)
    values
        (?, ?)
Hibernate:
    insert
    into
        teacher
        (expertise, name)
    values
        (?, ?)
Hibernate:
    insert
    into
        period
        (period)
    values
        (?)
Hibernate:
    insert
    into
        period_teacher
        (period_id, teachers_id)
    values
        (?, ?)
Hibernate:
    insert
    into
        period_teacher
        (period_id, teachers_id)
    values
        (?, ?)

Output in the database

period table

jpa one-to-many

teacher table

jpa one-to-many

period_teacher table

jpa one-to-many

Thanks for reading.

Leave a Reply

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