JPA One To Many Mapping

In the just previous chapter we have seen the One To One Mapping in JPA with example. In this chapter  we are looking into the One To Many mapping. As the name indicates  , one  parent entity instance will be having a list of instances of another entity . For example, consider an entity User . A user can have any number of Phone objects in it.The inverse Many To One relation is also possible . But there is no guarantee for the inverse relation.   In this chapter we are discussing  the  One To Many Mapping usage  in a JPA application with Open JPA as provider implementation.

JPA One To Many Mapping

Let us consider the relation ship between User and Phone entities.A User object can have a a collection of Phone objects in it. This is a simple One To Many relationship.Similarly a Phone object can have reference to a unique User object .If yes, then the inverse relationship is existing.  In this case , more than one Phone instances can have reference to  a single User object. So it is a Many To One relationship.In this chapter we are looking into examples with and without inverse relationship.The OneToMany mapping  can be done with @OneToMany   annotation or by using the one-to-one tag element  in case of XML mapping.

In this example , we are using the same workspace setup earlier. Here also OpenJPA is using as provider implementation.

Tools & Software Required

1)Eclipse Indigo – Download Link

2)Java EE SDK 1.6 –Download Link

3)MySQL Server 5.6 Community edition – Download Link

4)SQLYog Community Edition-Download Link

5)OpenJPA libray 2.1 – Download Link

SQL Queries

We are using the same database ‘JPASAMPLEDB‘ created earlier.

We can either use MySQL command line client or SQLYOG GUI for creating database and tables.

Let us create two tables USEDETAILS_TABLE and PHONEDETAILS_TABLE.The PHONEDETAILS_TABLE should have a foreign key to refer to the USERDETAILS_TABLE. The USER_ID from the USERDETAILS_TABLE is using as the foreign key in PHONEDETAILS_TABLE .

USE JPASAMPLEDB;

CREATE TABLE USERDETAILS_TABLE( `USER_ID` INT NOT NULL, `USER_NAME` VARCHAR(50) NOT NULL, `COUNTRY_NAME` VARCHAR(50) NOT NULL,`STATE_NAME` VARCHAR(50) NOT NULL, PRIMARY KEY (`USER_ID`) );

CREATE TABLE PHONEDETAILS_TABLE( `PHONE_ID` INT NOT NULL, `PHONE_NUMBER` VARCHAR(50) NOT NULL, `PHONE_TYPE` VARCHAR(50) NOT NULL,`USER_ID` INT NOT NULL, PRIMARY KEY (`PHONE_ID`) );

case 1)when there is inverse Many To One relation

persistence.xml

org.apache.openjpa.persistence.PersistenceProviderImpl com.jpa.entity.User
com.jpa.entity.Phone

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.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity(name = "User")
@Table(name = "USERDETAILS_TABLE")
public class User implements Serializable {

/**
*
*/
private static final long serialVersionUID = 1L;
private int userId;
private String userName;
private String countryName;
private String stateName;
private Set phoneList = new HashSet();

public User() {

}

public User(String userName, String countryName, String stateName) {
this.userName = userName;
this.countryName = countryName;
this.stateName = stateName;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "USER_ID")
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 = "COUNTRY_NAME")
public String getCountryName() {
return countryName;
}

public void setCountryName(String countryName) {
this.countryName = countryName;
}

@Column(name = "STATE_NAME")
public String getStateName() {
return stateName;
}

public void setStateName(String stateName) {
this.stateName = stateName;
}

@OneToMany(mappedBy = "userDetails", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public Set getPhoneList() {
return phoneList;
}

public void addToPhoneList(Phone phone) {
phone.setUserDetails(this);
this.phoneList.add(phone);

}

public void setPhoneList(Set phoneList) {
this.phoneList = phoneList;
}

public String toString() {
return "[ User Name : " + getUserName() + "; User Id : " + getUserId()
+ " ; Country Name : " + getCountryName() + " ; State Name : "
+ getStateName() + " ; Phone Details : " + getPhoneList()
+ " ]";

}
}

Primary key generation strategy is specified as AUTO.Various primary key generation strategies are explained earlier. CascadeType is specified as ALL,means both parent entity and child entities will be cascaded together  for all operations.Other options were explained in the earlier chapter.

Phone.java

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity(name = "Phone")
@Table(name = "PHONEDETAILS_TABLE")
public class Phone implements Serializable {

/**
*
*/
private static final long serialVersionUID = 1L;
private int phoneid;
private String phoneNumber;
private String phoneType;
private User userDetails;

public Phone() {

}

public Phone(String phoneNumber, String phoneType) {
this.phoneNumber = phoneNumber;
this.phoneType = phoneType;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "PHONE_ID")
public int getPhoneid() {
return phoneid;
}

public void setPhoneid(int phoneid) {
this.phoneid = phoneid;
}

@Column(name = "PHONE_NUMBER")
public String getPhoneNumber() {
return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}

@Column(name = "PHONE_TYPE")
public String getPhoneType() {
return phoneType;
}

public void setPhoneType(String phoneType) {
this.phoneType = phoneType;
}

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "USER_ID", nullable = false)
public User getUserDetails() {
return userDetails;
}

public void setUserDetails(User userDetails) {
this.userDetails = userDetails;
}

public int hashCode() {
return 10;
}

public boolean equals(Object object) {
boolean status = false;
Phone phone = (Phone) object;
if (phone.getPhoneNumber().equalsIgnoreCase(getPhoneNumber())
&& phone.getPhoneType().equalsIgnoreCase(getPhoneType())) {
status = true;
}
return status;
}

public String toString() {
return "[ Phone ID :" + getPhoneid() + " ; Phone Number :"
+ getPhoneNumber() + "; Phone Type :" + getPhoneType()
+ "; User Details: [User Id : " + getUserDetails().getUserId() + "] ]";
}
}

OneToManySample.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 com.jpa.entity.Phone;
import com.jpa.entity.User;

public class OneToManySample {

public OneToManySample() {

}

public void doInsert() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
// First user
User user = new User("Bijoy", "India", "Kerala");
Phone phone = new Phone("91-000-0-000000", "VOIP");
Phone phone1 = new Phone("91-0000000000", "MOBILE");
user.addToPhoneList(phone);
user.addToPhoneList(phone1);
// Second user
User user1 = new User("Renjith", "India", "Kerala");
Phone phone2 = new Phone("91-000-0-000001", "VOIP");
Phone phone3 = new Phone("91-0000000001", "LANDLINE");
user1.addToPhoneList(phone2);
user1.addToPhoneList(phone3);
EntityTransaction transaction = entitymanager.getTransaction();
transaction.begin();
entitymanager.persist(user);
entitymanager.persist(user1);
transaction.commit();
System.out.println("Done..");

}
}

public void fetchUserDetails() {
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 fetchPhoneDetails() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
EntityTransaction readTransaction = entitymanager.getTransaction();
readTransaction.begin();
Query query = entitymanager
.createQuery("select phone FROM Phone phone");
List list = query.getResultList();
Iterator iterator = list.iterator();
System.out.println("Phone Details fetched from database : ");
while (iterator.hasNext()) {
Phone phone = (Phone) iterator.next();
System.out.println(phone);
}

readTransaction.commit();
System.out.println("Phone Details over");
}
}

public static void main(String[] args) {
OneToManySample sample = new OneToManySample();
sample.doInsert();
sample.fetchUserDetails();
sample.fetchPhoneDetails();
}

}

Output

Done..

User Details fetched from database :

[ User Name : Bijoy; User Id : 2601 ; Country Name : India ; State Name : Kerala ; Phone Details : [[ Phone ID  :2652 ; Phone Number :91-000-0-000000; Phone Type :VOIP; User Details: [User Id : 2601]  ], [ Phone ID  :2651 ; Phone Number :91-0000000000; Phone Type :MOBILE; User Details: [User Id : 2601]  ]] ]

[ User Name : Renjith; User Id : 2602 ; Country Name : India ; State Name : Kerala ; Phone Details : [[ Phone ID  :2654 ; Phone Number :91-000-0-000001; Phone Type :VOIP; User Details: [User Id : 2602]  ], [ Phone ID  :2653 ; Phone Number :91-0000000001; Phone Type :LANDLINE; User Details: [User Id : 2602]  ]] ]

User Details over

Phone Details fetched from database :

[ Phone ID  :2651 ; Phone Number :91-0000000000; Phone Type :MOBILE; User Details: [User Id : 2601]  ]

[ Phone ID  :2652 ; Phone Number :91-000-0-000000; Phone Type :VOIP; User Details: [User Id : 2601]  ]

[ Phone ID  :2653 ; Phone Number :91-0000000001; Phone Type :LANDLINE; User Details: [User Id : 2602]  ]

[ Phone ID  :2654 ; Phone Number :91-000-0-000001; Phone Type :VOIP; User Details: [User Id : 2602]  ]

Phone Details over

So each User object contains one or more Phone objects and each Phone object has a single user instance reference in it.Also one or more Phone instances are referring to a single User reference. Thus the One To Many relation and the inverse Many To One relations are satisfied.

Case 2 ) When there is no inverse relation

Now consider a situation where each User object as one or more Phone objects and  there is no reference to User from Phone object, then that is a unidirectional relationship. In this case only One To Many relationship is existing.

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.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity(name = "User")
@Table(name = "USERDETAILS_TABLE")
public class User implements Serializable {

/**
*
*/
private static final long serialVersionUID = 1L;
private int userId;
private String userName;
private String countryName;
private String stateName;
private Set phoneList = new HashSet();

public User() {

}

public User(String userName, String countryName, String stateName) {
this.userName = userName;
this.countryName = countryName;
this.stateName = stateName;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "USER_ID")
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 = "COUNTRY_NAME")
public String getCountryName() {
return countryName;
}

public void setCountryName(String countryName) {
this.countryName = countryName;
}

@Column(name = "STATE_NAME")
public String getStateName() {
return stateName;
}

public void setStateName(String stateName) {
this.stateName = stateName;
}

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name="USER_ID")
public Set getPhoneList() {
return phoneList;
}

public void addToPhoneList(Phone phone) {
this.phoneList.add(phone);

}

public void setPhoneList(Set phoneList) {
this.phoneList = phoneList;
}

public String toString() {
return "[ User Name : " + getUserName() + "; User Id : " + getUserId()
+ " ; Country Name : " + getCountryName() + " ; State Name : "
+ getStateName() + " ; Phone Details : " + getPhoneList()
+ " ]";

}
}

Phone.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 = "Phone")
@Table(name = "PHONEDETAILS_TABLE")
public class Phone implements Serializable {

/**
*
*/
private static final long serialVersionUID = 1L;
private int phoneid;
private String phoneNumber;
private String phoneType;

public Phone() {

}

public Phone(String phoneNumber, String phoneType) {
this.phoneNumber = phoneNumber;
this.phoneType = phoneType;
}

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "PHONE_ID")
public int getPhoneid() {
return phoneid;
}

public void setPhoneid(int phoneid) {
this.phoneid = phoneid;
}

@Column(name = "PHONE_NUMBER")
public String getPhoneNumber() {
return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}

@Column(name = "PHONE_TYPE")
public String getPhoneType() {
return phoneType;
}

public void setPhoneType(String phoneType) {
this.phoneType = phoneType;
}

public int hashCode() {
return 10;
}

public boolean equals(Object object) {
boolean status = false;
Phone phone = (Phone) object;
if (phone.getPhoneNumber().equalsIgnoreCase(getPhoneNumber())
&& phone.getPhoneType().equalsIgnoreCase(getPhoneType())) {
status = true;
}
return status;
}

public String toString() {
return "[ Phone ID :" + getPhoneid() + " ; Phone Number :"
+ getPhoneNumber() + "; Phone Type :" + getPhoneType() + "]";
}
}

Lets see the class with main. There are methods to insert and fetch objects.

OneToManyUD.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 com.jpa.entity.Phone;
import com.jpa.entity.User;

public class OneToManyUD {
public OneToManyUD() {

}

public void doInsert() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
// First user
User user = new User("JAKS", "India", "Kerala");
Phone phone = new Phone("91-000-0-000001", "VOIP");
Phone phone1 = new Phone("91-0000000002", "MOBILE");
user.addToPhoneList(phone);
user.addToPhoneList(phone1);
// Second user
User user1 = new User("Karthik", "India", "Kerala");
Phone phone2 = new Phone("91-000-0-000003", "VOIP");
Phone phone3 = new Phone("91-0000000004", "LANDLINE");
user1.addToPhoneList(phone2);
user1.addToPhoneList(phone3);
EntityTransaction transaction = entitymanager.getTransaction();
transaction.begin();
entitymanager.persist(user);
entitymanager.persist(user1);
transaction.commit();
System.out.println("Done..");

}
}

public void fetchUserDetails() {
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 fetchPhoneDetails() {
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("OpenJPASample");
EntityManager entitymanager = entityManagerFactory
.createEntityManager();
if (null != entitymanager) {
EntityTransaction readTransaction = entitymanager.getTransaction();
readTransaction.begin();
Query query = entitymanager
.createQuery("select phone FROM Phone phone");
List list = query.getResultList();
Iterator iterator = list.iterator();
System.out.println("Phone Details fetched from database : ");
while (iterator.hasNext()) {
Phone phone = (Phone) iterator.next();
System.out.println(phone);
}
readTransaction.commit();
System.out.println("Phone Details over");
}
}

public static void main(String[] args) {
OneToManyUD sample = new OneToManyUD();
sample.doInsert();
sample.fetchUserDetails();
sample.fetchPhoneDetails();
}

}

Output

Done..

User Details fetched from database :

[ User Name : JAKS; User Id : 2701 ; Country Name : India ; State Name : Kerala ; Phone Details : [[ Phone ID  :2752 ; Phone Number :91-000-0-000001; Phone Type :VOIP], [ Phone ID  :2751 ; Phone Number :91-0000000002; Phone Type :MOBILE]] ]

[ User Name : Karthik; User Id : 2702 ; Country Name : India ; State Name : Kerala ; Phone Details : [[ Phone ID  :2754 ; Phone Number :91-000-0-000003; Phone Type :VOIP], [ Phone ID  :2753 ; Phone Number :91-0000000004; Phone Type :LANDLINE]] ]

User Details over

Phone Details fetched from database :

[ Phone ID  :2751 ; Phone Number :91-0000000002; Phone Type :MOBILE]

[ Phone ID  :2752 ; Phone Number :91-000-0-000001; Phone Type :VOIP]

[ Phone ID  :2753 ; Phone Number :91-0000000004; Phone Type :LANDLINE]

[ Phone ID  :2754 ; Phone Number :91-000-0-000003; Phone Type :VOIP]

Phone Details over

Each User object has one or more Phone objects in it . And Phone objects does not contain any  User objects. So the relationship is only unidirectional.

See  Related Topics

JPA Overview

JPA Example – Insert/Read

find method in JPA example

JPA Update Example

JPA Delete EXample

JPQL

JPQL Update Query Example

JPQL Delete Query

Caching

Overview to caching in JPA

Locking in JPA

Data  Locking in JPA

JPA Mapping Schemes

One To One Mapping in JPA

Many To One Mapping in JPA

Many To Many Mapping in JPA