JPA Relationship Annotations Example
Here we will look into the JPA Relationship Annotations. This article takes you through the relationships between Entities. Generally the relations are more effective between tables in the database and as We already know that in RDBMS every entity(table) must be related to other entities to become meaningful. Here the entity classes are treated as relational tables (concept of JPA).
The relationships between Entity classes are as follows:
@ManyToOne Relation
@OneToMany Relation
@OneToOne Relation
@ManyToMany Relation
We will look into each of them.
1. The Database
For the sake of simplicity we will use the Oracle Database. We will create separate schema with ER-Diagram for each of the topics (relationship types) to help you understand.
2. Many to One Relation
2.1 The Database Schema & ER Diagram
A many to one relationship can occur when many entities of the source table is related to one entity of the target table. For example many employee can work in a single department.
2.1.1 The ER Diagram
2.1.2 The Tables
department1.sql
create table department(did number(3) primary key, dname varchar2(25));
employee1.sql
create table employee(eid number(3) primary key, ename varchar2(25), salary number(7), job_id number(3), did number(3) references department(did) on delete set null);
2.2 The Java Code
2.2.1 Unidirectional Single Valued Mapping
A unidirectional many to one relationships in JPA2 is defined by simply annotating the attribute in the Source
entity that refers to the target entity with @ManyToOne
annotation. Have a look to the figure below, The important thing to notice in the figure is that the arrow head points from Employee
to Department
and not the other way round.
The example below shows the Employee
entity that has a unidirectional ManyToOne
association with the Department
entity.
Department.java
package com.javacodegeeks.examples.rivu.jpa.entity; import java.io.Serializable; import javax.persistence.*; /** * Entity implementation class for Entity: Department * */ @Entity public class Department implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy= GenerationType.AUTO) private int did; private String dname; public Department() { super(); } public Department(int did, String dname) { super(); this.did = did; this.dname = dname; } public int getDid() { return did; } public void setDid(int did) { this.did = did; } public String getDname() { return dname; } public void setDname(String dname) { this.dname = dname; } }
Employee.java
package com.javacodegeeks.examples.rivu.jpa.entity; import java.io.Serializable; import javax.persistence.*; /** * Entity implementation class for Entity: Employee * */ @Entity public class Employee implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy= GenerationType.AUTO) private int eid; private String ename; private double salary; private int job_id; @ManyToOne @JoinColumn(name="did") private Department department; public Employee() { super(); } public int getEid() { return eid; } public void setEid(int eid) { this.eid = eid; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public int getJob_id() { return job_id; } public void setJob_id(int job_id) { this.job_id = job_id; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public Employee(int eid, String ename, double salary, int job_id, Department department) { super(); this.eid = eid; this.ename = ename; this.salary = salary; this.job_id = job_id; this.department = department; } }
ManytoOneService.java
package com.javacodegeeks.examples.rivu.jpa.service; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import com.javacodegeeks.examples.rivu.jpa.entity.Employee; import com.javacodegeeks.examples.rivu.jpa.entity.Department; public class ManytoOneService { public static void main(String[] args) { EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "RivuChk_JPA" ); EntityManager entitymanager = emfactory.createEntityManager( ); entitymanager.getTransaction( ).begin( ); Department department = entitymanager.find(Department.class, 1); System.out.println("Department: "+department.getDname()); entitymanager.getTransaction( ).commit( ); entitymanager.getTransaction( ).begin( ); entitymanager.persist(department); Employee employee = new Employee(); employee.setEname("Rivu"); employee.setSalary(25000); employee.setJob_id(1); employee.setDepartment(department); entitymanager.persist(employee); int employeeId = employee.getEid(); entitymanager.getTransaction().commit(); entitymanager.getTransaction().begin(); Employee dbEmployee =entitymanager.find(Employee.class, employeeId); System.out.println("Employee " + dbEmployee); entitymanager.getTransaction().commit(); entitymanager.close(); emfactory.close(); } }
2.3 Output
[EL Fine]: sql: 2015-04-12 22:19:06.071--ServerSession(2059904228)--Connection(2095602418)--Thread(Thread[main,5,main])--SELECT DID, DNAME FROM DEPARTMENT WHERE (DID = ?) bind => [1] Department: IT Software [EL Fine]: sql: 2015-04-12 22:19:06.088--ClientSession(1469235340)--Connection(2095602418)--Thread(Thread[main,5,main])--INSERT INTO EMPLOYEE (EID, ENAME, JOB_ID, SALARY, did) VALUES (?, ?, ?, ?, ?) bind => [601, Rivu, 1, 25000.0, 1] Employee [ id=601 ename=Rivu salary=25000.0 jobid=1 Department=[ id=1 dname=IT Software]]
3. One to Many Relation
3.1 The Database Schema & ER Diagram
A one to many relationship can occur when one entity of the source table is related to many entities of the target table. For example one employee can work in multiple projects.
Its a vice versa of ManytoOne
relation. It depends on which side of the relationship the entity is present on.
3.1.1 The ER Diagram
3.1.2 The Tables
projects1.sql
create table projects(p_id number(3) primary key, title varchar2(25), eid number(3) references employee(eid) on delete set null);
employee1.sql
create table employee(eid number(3) primary key, ename varchar2(25), salary number(7), job_id number(3), did number(3) references department(did) on delete set null);
3.2 The Java Code
The example below shows the Employee
entity that has a Bidirectional OneToMany
association with the Projects
entity.
Projects.java
package com.javacodegeeks.examples.rivu.jpa.entity; import java.io.Serializable; import javax.persistence.*; /** * Entity implementation class for Entity: Department * */ @Entity public class Projects implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy= GenerationType.AUTO) private int p_id; private String title; @ManyToOne @JoinColumn(name="eid") private Employee employee; public Projects() { super(); } public Projects(int p_id, String title, Employee employee) { super(); this.p_id = p_id; this.title = title; this.employee = employee; } public int getP_id() { return p_id; } public void setP_id(int p_id) { this.p_id = p_id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } @Override public String toString() { return "[Project ID="+p_id+" Title="+title+" ]"; } }
Employee.java Modified
package com.javacodegeeks.examples.rivu.jpa.entity; import java.io.Serializable; import java.util.List; import javax.persistence.*; /** * Entity implementation class for Entity: Employee * */ @Entity public class Employee implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy= GenerationType.AUTO) private int eid; private String ename; private double salary; private int job_id; @ManyToOne @JoinColumn(name="did") private Department department; @OneToMany @JoinColumn(name="eid") private List projects; public Employee() { super(); } public int getEid() { return eid; } public void setEid(int eid) { this.eid = eid; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public int getJob_id() { return job_id; } public void setJob_id(int job_id) { this.job_id = job_id; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public Employee(int eid, String ename, double salary, int job_id, Department department) { super(); this.eid = eid; this.ename = ename; this.salary = salary; this.job_id = job_id; this.department = department; } public List getProjects() { return projects; } public void setProjects(List projects) { this.projects = projects; } @Override public String toString() { return "[ id="+eid+" ename="+ename+" salary="+salary+" jobid="+job_id+" Department="+department+"]"; } }
OnetoManyService.java
package com.javacodegeeks.examples.rivu.jpa.service; import java.util.Iterator; import java.util.List; import java.util.Scanner; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import com.javacodegeeks.examples.rivu.jpa.entity.Employee; import com.javacodegeeks.examples.rivu.jpa.entity.Department; import com.javacodegeeks.examples.rivu.jpa.entity.Projects; public class OnetoManyService { public static void main(String[] args) { // TODO Auto-generated method stub Scanner sc=new Scanner(System.in); EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "RivuChk_JPA" ); EntityManager entitymanager = emfactory.createEntityManager( ); entitymanager.getTransaction( ).begin( ); System.out.println("Enter Employee ID"); int eid=sc.nextInt(); Employee emp = entitymanager.find(Employee.class, eid); System.out.println("Employee: "+emp.toString()); List projects=emp.getProjects(); Iterator ps=projects.iterator(); int count=0; while(ps.hasNext()) { System.out.println("Project "+(++count)+" : "+ps.next().toString()); } entitymanager.getTransaction( ).commit( ); entitymanager.close(); emfactory.close(); } }
3.3 Output
[EL Fine]: sql: 2015-05-22 21:48:01.564--ServerSession(853119666)--Connection(1177903557)--Thread(Thread[main,5,main])--SELECT * FROM SEQUENCE WHERE SEQ_NAME = SEQ_GEN Enter Employee ID 401 [EL Fine]: sql: 2015-05-22 21:48:04.139--ServerSession(853119666)--Connection(1177903557)--Thread(Thread[main,5,main])--SELECT EID, ENAME, JOB_ID, SALARY, did FROM EMPLOYEE WHERE (EID = ?) bind => [401] [EL Fine]: sql: 2015-05-22 21:48:04.146--ServerSession(853119666)--Connection(1177903557)--Thread(Thread[main,5,main])--SELECT DID, DNAME FROM DEPARTMENT WHERE (DID = ?) bind => [1] Employee: [ id=401 ename=Rivu salary=20000.0 jobid=1 Department=[ id=1 dname=HR]] [EL Fine]: sql: 2015-05-22 21:48:04.157--ServerSession(853119666)--Connection(1177903557)--Thread(Thread[main,5,main])--SELECT P_ID, TITLE, eid FROM PROJECTS WHERE (eid = ?) bind => [401] Project 1 : [Project ID=2 Title=www.vracommunity.com ] Project 2 : [Project ID=1 Title=Android App Project ]
3.4 Explanation
In Projects.java
We used @ManyToOne
notation to map Employee entity with Projects entity in ManyToOne
relation.
We modified the Employee.java, used @OneToMany
for Bi-directional mapping with the Project
class.
Thus whenever we select a record from the employee table, the related records from the projects table is also selected automatically.
4. One to One Relation
4.1 The Database Schema & ER Diagram
A one to one relationship can occur when one entity of the source table is related to only one entity of the target table. For example one employee can can do a single job.
4.1.1 The ER Diagram
4.1.2 The Tables
job1.sql
create table job(job_id number(3) primary key, designation varchar2(25));
We have to make a small alteration to the employee table
employee2.sql
alter table employee modify(job_id number(3) references job(job_id));
4.2 The Java Code
The example below shows the Employee
entity that has a bidirectional OneToOne
association with the Job
entity.
Job.java
package com.javacodegeeks.examples.rivu.jpa.entity; import java.io.Serializable; import javax.persistence.*; /** * Entity implementation class for Entity: Job * */ @Entity public class Job implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy= GenerationType.AUTO) private int job_id; private String designation; @OneToOne(mappedBy="job") private Employee employee; public Job() { super(); } public Job(int job_id, String designation) { super(); this.job_id = job_id; this.designation = designation; } public int getJob_id() { return job_id; } public void setJob_id(int job_id) { this.job_id = job_id; } public String getDesignation() { return designation; } public void setDesignation(String designation) { this.designation = designation; } public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } @Override public String toString() { return "[ job_id="+job_id+" Designation="+designation+" ]"; } }
We have to modify the Employee.java
again, to change the int job_id;
to Job job;
. You can easily get the changes as old codes are commented out.
Employee.java
package com.javacodegeeks.examples.rivu.jpa.entity; import java.io.Serializable; import java.util.List; import javax.persistence.*; /** * Entity implementation class for Entity: Employee * */ @Entity public class Employee implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy= GenerationType.AUTO) private int eid; private String ename; private double salary; //private int job_id; @ManyToOne @JoinColumn(name="did") private Department department; @OneToOne @JoinColumn(name="job_id") private Job job; @OneToMany @JoinColumn(name="eid") private List projects; public Employee() { super(); } public int getEid() { return eid; } public void setEid(int eid) { this.eid = eid; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } /* public int getJob_id() { return job_id; } public void setJob_id(int job_id) { this.job_id = job_id; } */ public Job getJob() { return job; } public void setJob(Job job) { this.job = job; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public Employee(int eid, String ename, double salary, Job job, Department department) { super(); this.eid = eid; this.ename = ename; this.salary = salary; this.job = job; this.department = department; } public List getProjects() { return projects; } public void setProjects(List projects) { this.projects = projects; } @Override public String toString() { return "[ id="+eid+" ename="+ename+" salary="+salary+" job="+job.toString()+" Department="+department+"]"; } }
OnetoOneService.java
package com.javacodegeeks.examples.rivu.jpa.service; import java.util.Iterator; import java.util.List; import java.util.Scanner; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import com.javacodegeeks.examples.rivu.jpa.entity.Employee; import com.javacodegeeks.examples.rivu.jpa.entity.Department; import com.javacodegeeks.examples.rivu.jpa.entity.Job; import com.javacodegeeks.examples.rivu.jpa.entity.Projects; public class OnetoOneService { public static void main(String[] args) { Scanner sc=new Scanner(System.in); EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "RivuChk_JPA" ); EntityManager entitymanager = emfactory.createEntityManager( ); entitymanager.getTransaction( ).begin( ); System.out.println("Enter Job ID"); int jid=sc.nextInt(); Job job = entitymanager.find(Job.class, jid); System.out.println("Job: "+job.toString()); Employee emp=job.getEmployee(); System.out.println("Employee: "+emp.toString()); entitymanager.getTransaction( ).commit( ); entitymanager.close(); emfactory.close(); } }
4.3 Output
[EL Fine]: sql: 2015-05-23 16:20:56.656--ServerSession(559670971)--Connection(879292014)--Thread(Thread[main,5,main])--SELECT * FROM SEQUENCE WHERE SEQ_NAME = SEQ_GEN Enter Job ID 1 [EL Fine]: sql: 2015-05-23 16:20:59.684--ServerSession(559670971)--Connection(879292014)--Thread(Thread[main,5,main])--SELECT JOB_ID, DESIGNATION FROM JOB WHERE (JOB_ID = ?) bind => [1] [EL Fine]: sql: 2015-05-23 16:20:59.726--ServerSession(559670971)--Connection(879292014)--Thread(Thread[main,5,main])--SELECT EID, ENAME, SALARY, did, job_id FROM EMPLOYEE WHERE (job_id = ?) bind => [1] [EL Fine]: sql: 2015-05-23 16:20:59.745--ServerSession(559670971)--Connection(879292014)--Thread(Thread[main,5,main])--SELECT DID, DNAME FROM DEPARTMENT WHERE (DID = ?) bind => [1] Job: [ job_id=1 Designation=Software Engineer ] Employee: [ id=101 ename=Illias salary=20000.0 job=[ job_id=1 Designation=Software Engineer ] Department=[ id=1 dname=HR]]
5. Download
This was an example of JPA Relationship Annotations.