So far we discussed the One To One Mapping and One To Many Mappings in JPA.in this chapter we are discussing the Many To Many mapping in JPA. In a Many To Many relationship there are source objects and each source object contains a collection of child objects.And each child object can be the child of any number of source objects .
JPA Many To Many Mapping
In this chapter we are discussing the concept with an example.Consider and example of a social network user and the various user groups in the social network application.Each user can become the member in any number of groups.Each group contains any number of users. The Many To Many mapping is doing either by the @ManyToMany annotation or by the many-to-many XML element.
To implement Many To Many relationship there should a dedicated table for source objects and another table for child objects.In addition , there should be an intermediate table for doing the mapping. So lets create the tables first.We are using the same ‘jpasampledb‘ database we created earlier.
Queries for creating tables
1)Create table for storing user details
CREATE TABLE USER_TABLE( `USER_ID` INT NOT NULL, `USER_NAME` VARCHAR(50) NOT NULL, `FIRST_NAME` VARCHAR(50) NOT NULL,`LAST_NAME` VARCHAR(50) NOT NULL, PRIMARY KEY (`USER_ID`) );
2)Create table for storing group details
CREATE TABLE GROUPS_TABLE( `GROUP_ID` INT NOT NULL, `GROUP_NAME` VARCHAR(50) NOT NULL, `GROUP_TYPE` VARCHAR(50) NOT NULL, PRIMARY KEY (`GROUP_ID`) );
3)Create intermediate table for storing the mapping details
CREATE TABLE USERGROUPS_TABLE( `USER_ID` INT NOT NULL, `GROUP_ID` INT NOT NULL);
Now let us look into the coding side.We have two entity classes , User.java and Group.java. Each User object contains a number of Group objects. Each individual can become the child object of any other User object.
We are using the same workspace we set up earlier. Also OpenJPA is using as provider.
1)Uni Directional Many To Many Relation
Let us discuss the unidirectional Many To Many relationship. So each User object can have any number of Group objects. The same Group object may become the child of any number of other User objects.In the case of unidirectional relation , the child object does not have any reference to source objects.
User.java
import java.io.Serializable;
import java.util.HashSet;
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.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity(name = "user")
@Table(name = "user_table")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int userId;
private String userName;
private String firstName;
private String lastName;
private Set
public User() {
}
public User(String userName, String firstName, String lastName,Set
this.userName = userName;
this.firstName = firstName;
this.lastName = lastName;
this.userGroups = groups;
}
@Id
@Column(name = "USER_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
@Column(name = "USER_NAME")
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Column(name = "FIRST_NAME")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Column(name = "LAST_NAME")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@ManyToMany
@JoinTable(name = "USERGROUPS_TABLE", joinColumns = { @JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "GROUP_ID", referencedColumnName = "GROUP_ID") })
public Set
return userGroups;
}
public void setUserGroups(Set
this.userGroups = userGroups;
}
public String toString() {
return "[ UserId = " + getUserId() + " ; User Name = " + getUserName()
+ " ; First Name = " + getFirstName() + " ; Last Name = "
+ getLastName() + "; Groups : " + getUserGroups() + " ]";
}
}
The mapping is done by using the @ManyToMany annotation. The intermediate table details are mapped by using the @JoinTable annotation.
Group.java
import java.io.Serializable;
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(name = "Group")
@Table(name = "GROUPS_TABLE")
public class Group implements Serializable {
private static final long serialVersionUID = 1L;
private int groupId;
private String groupName;
private String groupType;
public Group() {
}
public Group(String groupName, String groupType) {
this.groupName = groupName;
this.groupType = groupType;
}
@Id
@Column(name = "GROUP_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}
@Column(name = "GROUP_NAME")
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
@Column(name = "GROUP_TYPE")
public String getGroupType() {
return groupType;
}
public void setGroupType(String groupType) {
this.groupType = groupType;
}
public int hashCode() {
return 10;
}
public boolean equals(Object group) {
boolean status = false;
if (getGroupName().equalsIgnoreCase(((Group) group).getGroupName())) {
status = true;
}
return status;
}
public String toString() {
return " [ " + " Group Id = " + getGroupId() + " ; Group Name = "
+ getGroupName() + " ;Group Type = " + getGroupType() + " ] ";
}
}
Lets see the persistence.xml
persistence.xml
Now lets see the main class . It simply creates a number of User and Group objects . Then associating the User and Group objects and persisting to database. Then fetching from database.
Many2ManySample.java
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import com.jpa.many2many.entities.Group;
import com.jpa.many2many.entities.User;
public class Many2ManySample {
public Many2ManySample() {
}
public void insertUserGroups() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
Group group1 = new Group("Group1", "Friends");
Group group2 = new Group("Group2", "Friends");
Group group3 = new Group("Group3", "Relatives");
EntityTransaction transaction = entitymanager.getTransaction();
transaction.begin();
entitymanager.persist(group1);
entitymanager.persist(group2);
entitymanager.persist(group3);
transaction.commit();
}
}
public void insertUsers() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
EntityTransaction readTransaction = entitymanager.getTransaction();
readTransaction.begin();
CriteriaQuery
.createQuery(Group.class);
criteria.select(criteria.from(Group.class));
List
.getResultList();
Iterator iterator = list.iterator();
Set
Set
while (iterator.hasNext()) {
Group group = (Group) iterator.next();
if (group.getGroupName().equalsIgnoreCase("Group1")) {
groups1.add(group);
} else if (group.getGroupName().equalsIgnoreCase("Group2")) {
groups1.add(group);
groups2.add(group);
} else if (group.getGroupName().equalsIgnoreCase("Group3")) {
groups2.add(group);
}
}
readTransaction.commit();
User user1 = new User("sams", "Samuel", "Johnson", groups1);
User user2 = new User("mike", "Mike", "William", groups2);
EntityTransaction insertTransaction = entitymanager
.getTransaction();
insertTransaction.begin();
entitymanager.persist(user1);
entitymanager.persist(user2);
insertTransaction.commit();
System.out.println("User details succesfully inserted");
}
}
public void fetchUsers() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
EntityTransaction readTransaction = entitymanager.getTransaction();
readTransaction.begin();
Query query = entitymanager
.createQuery("select user FROM user user");
List list = query.getResultList();
Iterator iterator = list.iterator();
System.out.println("User Details fetched from database : ");
while (iterator.hasNext()) {
User user = (User) iterator.next();
System.out.println(user);
}
readTransaction.commit();
System.out.println("User Details over..");
}
}
public static void main(String[] args) {
Many2ManySample sample = new Many2ManySample();
sample.insertUserGroups();
sample.insertUsers();
sample.fetchUsers();
}
}
Output
User details succesfully inserted
User Details fetched from database :
[ UserId = 3701 ; User Name = sams ; First Name = Samuel ; Last Name = Johnson; Groups : [ [ Group Id = 3651 ; Group Name = Group1 ;Group Type = Friends ] , [ Group Id = 3652 ; Group Name = Group2 ;Group Type = Friends ] ] ]
[ UserId = 3702 ; User Name = mike ; First Name = Mike ; Last Name = William; Groups : [ [ Group Id = 3652 ; Group Name = Group2 ;Group Type = Friends ] , [ Group Id = 3653 ; Group Name = Group3 ;Group Type = Relatives ] ] ]
User Details over..
The screenshot of database tables are given below.
Contents in user_table
USER_ID USER_NAME FIRST_NAME LAST_NAME
——- ——— ———- ———–
3601 sams Samuel Johnson
3602 mike Mike William
Contents in groups_table
GROUP_ID GROUP_NAME GROUP_TYPE
——– ———- ———–
3651 Group1 Friends
3652 Group2 Friends
3653 Group3 Relatives
Contents in usergroups_table
USER_ID GROUP_ID
——- ———-
3701 3652
3701 3651
3702 3653
3702 3652
2)Bi Directional Many To Many Relation
Now let us consider the bi directional many to many mapping.There are slight changes in the entity classes and main class.
User.java
import java.io.Serializable;
import java.util.HashSet;
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(name = "user")
@Table(name = "user_table")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int userId;
private String userName;
private String firstName;
private String lastName;
private Set
public User() {
}
public User(String userName, String firstName, String lastName) {
this.userName = userName;
this.firstName = firstName;
this.lastName = lastName;
}
@Id
@Column(name = "USER_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
@Column(name = "USER_NAME")
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Column(name = "FIRST_NAME")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Column(name = "LAST_NAME")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "USERGROUPS_TABLE", joinColumns = { @JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "GROUP_ID", referencedColumnName = "GROUP_ID") })
public Set
return userGroups;
}
public void setUserGroups(Set
this.userGroups = userGroups;
}
public void addToGroups(Group group) {
this.userGroups.add(group);
group.addUser(this);
}
public int hashCode() {
return 10;
}
public boolean equals(Object object) {
User user = (User) object;
boolean equality = false;
if (getFirstName().equalsIgnoreCase(user.getFirstName())
&& getLastName().equalsIgnoreCase(user.getLastName())) {
equality = true;
}
return equality;
}
public String toString() {
String userGroups = "";
for (Group group : getUserGroups()) {
userGroups = userGroups + "Group Name = " + group.getGroupName()
+ " ; ";
}
return "[ UserId = " + getUserId() + " ; User Name = " + getUserName()
+ " ; First Name = " + getFirstName() + " ; Last Name = "
+ getLastName() + "User Groups : " + userGroups + " ]";
}
}
Group.java
import java.io.Serializable;
import java.util.HashSet;
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.ManyToMany;
import javax.persistence.Table;
@Entity(name = "Group")
@Table(name = "GROUPS_TABLE")
public class Group implements Serializable {
private static final long serialVersionUID = 1L;
private int groupId;
private String groupName;
private String groupType;
private Set
public Group() {
}
public Group(String groupName, String groupType) {
this.groupName = groupName;
this.groupType = groupType;
}
@Id
@Column(name = "GROUP_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}
@Column(name = "GROUP_NAME")
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
@Column(name = "GROUP_TYPE")
public String getGroupType() {
return groupType;
}
public void setGroupType(String groupType) {
this.groupType = groupType;
}
public int hashCode() {
return 10;
}
public boolean equals(Object group) {
boolean status = false;
if (getGroupName().equalsIgnoreCase(((Group) group).getGroupName())) {
status = true;
}
return status;
}
@ManyToMany(mappedBy = "userGroups", cascade = CascadeType.ALL)
public Set
return users;
}
public void setUsers(Set
this.users = users;
}
public void addUser(User user) {
users.add(user);
}
public String toString() {
String userDetails = "";
for (User user : getUsers()) {
userDetails = userDetails + " User Name = "
+ user.getUserName()+ " ; ";
}
return " [ " + " Group Id = " + getGroupId() + " ; Group Name = "
+ getGroupName() + " ;Group Type = " + getGroupType()
+ " ; Member Details : " + userDetails + " ] ";
}
}
ManyToMany2DSample.java
import java.util.Iterator;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import com.jpa.many2many.entities.Group;
import com.jpa.many2many.entities.User;
public class ManyToMany2DSample {
public ManyToMany2DSample() {
}
public void insertUsers() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
Group group1 = new Group("Group1", "Friends");
Group group2 = new Group("Group2", "Friends");
Group group3 = new Group("Group3", "Relatives");
User user1 = new User("sams", "Samuel", "Johnson");
User user2 = new User("mike", "Mike", "William");
user1.addToGroups(group1);
user1.addToGroups(group2);
user2.addToGroups(group2);
user2.addToGroups(group3);
EntityTransaction transaction = entitymanager.getTransaction();
transaction.begin();
entitymanager.persist(user1);
entitymanager.persist(user2);
transaction.commit();
}
}
public void fetchUsers() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
EntityTransaction readTransaction = entitymanager.getTransaction();
readTransaction.begin();
Query query = entitymanager
.createQuery("select user FROM user user");
List list = query.getResultList();
Iterator iterator = list.iterator();
System.out.println("User Details fetched from database : ");
while (iterator.hasNext()) {
User user = (User) iterator.next();
System.out.println(user);
}
readTransaction.commit();
System.out.println("User Details over..");
}
}
public void fetchGroups() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
EntityTransaction readTransaction = entitymanager.getTransaction();
readTransaction.begin();
CriteriaQuery
.createQuery(Group.class);
criteria.select(criteria.from(Group.class));
List
.getResultList();
Iterator iterator = list.iterator();
System.out.println("Group Details fetched from database : ");
while (iterator.hasNext()) {
Group group = (Group) iterator.next();
System.out.println(group);
}
readTransaction.commit();
System.out.println("Group Details over..");
}
}
public static void main(String[] args) {
ManyToMany2DSample sample = new ManyToMany2DSample();
sample.insertUsers();
sample.fetchUsers();
sample.fetchGroups();
}
}
Output
User Details fetched from database :
[ UserId = 4051 ; User Name = sams ; First Name = Samuel ; Last Name = JohnsonUser Groups : Group Name = Group1 ; Group Name = Group2 ; ]
[ UserId = 4052 ; User Name = mike ; First Name = Mike ; Last Name = WilliamUser Groups : Group Name = Group2 ; Group Name = Group3 ; ]
User Details over..
Group Details fetched from database :
[ Group Id = 4101 ; Group Name = Group2 ;Group Type = Friends ; Member Details : User Name = mike ; User Name = sams ; ]
[ Group Id = 4102 ; Group Name = Group1 ;Group Type = Friends ; Member Details : User Name = sams ; ]
[ Group Id = 4103 ; Group Name = Group3 ;Group Type = Relatives ; Member Details : User Name = mike ; ]
Group Details over..
See Related Topics
JPQL
Caching
Locking in JPA
JPA Mapping Schemes