In previous articles we have seen One to One and One to Many mappings in JPA. In this article we will see how to configure and use Many to Many mappings in JPA.

We have two entities Employee and Project, one employee can be a part of more than one project and a Project can have multiple Employees. We will implement this scenario with many to many mapping using a third mapping table.
See the annotations and entity structure below:

Employee.java


Employee.java

package com.tbNext.hb.models;

import java.util.Set;

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 = "TB_EMPLOYEE")
public class Employee {

	@Id
	@Column(name = "ID")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

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

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

	@Column(name = "EMAIL")
	private String email;

	@Column(name = "PHONE")
	private String phone;

	@ManyToMany(cascade = CascadeType.ALL)
	@JoinTable(name = "EMPLOYEE_PROJECTS", joinColumns = { @JoinColumn(name = "EMPLOYEE_ID", referencedColumnName = "ID") }, inverseJoinColumns = { @JoinColumn(name = "PROJECT_ID", referencedColumnName = "ID") })
	Set<Project> projects;

	public Employee() {
		super();
	}

	public Employee(String firstName, String lastName, String email,
			String phone) {
		super();
		this.firstName = firstName;
		this.lastName = lastName;
		this.email = email;
		this.phone = phone;
	}

	// getter and setters including projects

	public String toString() {
		return "[ID: " + id + " First Name: " + firstName + " Last Name: "
				+ lastName + " Email: " + email + " Phone: " + phone + "]";
	}
}
Employee entity is refining a new table name EMPLOYEE_PROJECTS using @JoinTable annotation, joinColumns attribute is refining two columns in EMPLOYEE_PROJECTS table, along with their name and respective primary key columns name in Employee and projects.

Projects.java


package com.tbNext.hb.models;

import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "TB_PROJECT")
public class Project {

	@Id
	@Column(name = "ID")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

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

	public Project() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Project(String name) {
		super();
		this.name = name;
	}

	@ManyToMany(mappedBy = "projects")
	Set<Employee> employees;

	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 Set<Employee> getEmployees() {
		return employees;
	}

	public void setEmployees(Set<Employee> employees) {
		this.employees = employees;
	}
}
We have used mappedBy attribute here, this indicates that this entity is mapped by other owner entity and this one is not responsible for the association.

Implementation

Now lets see things in action, we will have two employees and two projects, so every employee is part of two projects and each project is having two employees associated:

package com.tbNext.java;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.EntityManager;

import com.tbNext.hb.Utils.PersistenceManager;
import com.tbNext.hb.models.Employee;
import com.tbNext.hb.models.Project;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) {
		// getting instance of EntityManagerFactory
		EntityManager em = PersistenceManager.INSTANCE.getEntityManager();

		// create instances of Employee
		Employee employee1 = new Employee("Tech", "Burps",
				"info@tbNext.com", "8765234599");

		Employee employee2 = new Employee("Java", "GUys", "java@tbNext.com",
				"8987876758");

		// create instances of Project
		Project project1 = new Project("Automobile");
		Project project2 = new Project("Manufactoring");

		Set<Project> projects = new HashSet<Project>();
		projects.add(project1);
		projects.add(project2);

		employee1.setProjects(projects);
		employee2.setProjects(projects);

		// Adding entities to db
		em.getTransaction().begin();
		em.persist(employee1);
		em.persist(employee2);
		em.getTransaction().commit();

		// try to fetch employee1
		Employee emFromDb1 = em.find(Employee.class, employee1.getId());
		System.out.println("Employee Id: " + emFromDb1.getId()
				+ " No of Projects : " + emFromDb1.getProjects().size());

		// try to fetch employee2
		Employee emFromDb2 = em.find(Employee.class, employee1.getId());
		System.out.println("Employee Id: " + emFromDb2.getId()
				+ " No of Projects : " + emFromDb2.getProjects().size());

		// try to fetch address
		Project addressFromDb = em.find(Project.class, project1.getId());
		System.out.println("Address id: " + addressFromDb.getId());

	}
}
Output: We can see from the output, there is one more helping table created as passed in @JoinTable annotation, this table will have association mapping details:

Hibernate: create table EMPLOYEE_PROJECTS (EMPLOYEE_ID bigint not null, PROJECT_ID bigint not null, primary key (EMPLOYEE_ID, PROJECT_ID)) ENGINE=InnoDB
Hibernate: create table TB_EMPLOYEE (ID bigint not null auto_increment, EMAIL varchar(255), FIRST_NAME varchar(255), LAST_NAME varchar(255), PHONE varchar(255), primary key (ID)) ENGINE=InnoDB
Hibernate: create table TB_PROJECT (ID bigint not null auto_increment, NAME varchar(255), primary key (ID)) ENGINE=InnoDB
Hibernate: alter table EMPLOYEE_PROJECTS add constraint FKbryekhd63ksimyv21t5bv31r9 foreign key (PROJECT_ID) references TB_PROJECT (ID)
Hibernate: alter table EMPLOYEE_PROJECTS add constraint FKag5owb648j8quv9ya6eir7yn9 foreign key (EMPLOYEE_ID) references TB_EMPLOYEE (ID)
Sep 13, 2015 5:14:15 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: insert into TB_EMPLOYEE (EMAIL, FIRST_NAME, LAST_NAME, PHONE) values (?, ?, ?, ?)<>br /> Hibernate: insert into TB_PROJECT (NAME) values (?)
Hibernate: insert into TB_PROJECT (NAME) values (?)
Hibernate: insert into TB_EMPLOYEE (EMAIL, FIRST_NAME, LAST_NAME, PHONE) values (?, ?, ?, ?)
Hibernate: insert into EMPLOYEE_PROJECTS (EMPLOYEE_ID, PROJECT_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_PROJECTS (EMPLOYEE_ID, PROJECT_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_PROJECTS (EMPLOYEE_ID, PROJECT_ID) values (?, ?)
Hibernate: insert into EMPLOYEE_PROJECTS (EMPLOYEE_ID, PROJECT_ID) values (?, ?)
Employee Id: 1 No of Projects : 2
Employee Id: 1 No of Projects : 2
Address id: 2


That's it for this discussion, we are done with configuring many to many mappings using annotations using a third mapping table. In upcoming article we will see more about JPA, Hibernate and other technologies.

In this article we have seen, many to many mapping in JPA, in upcoming articles we will know more about JPA and other opensource technologies.
  • By Techburps.com
  • Oct 1, 2015
  • JPA