In this series of JPA tutorials we will see, Collection mappings, criteria queries, hql queries and inheritance strategies. In this particular article we are going to look into how to implement JPA one to one mapping using annotations.

1) Bi-directional one to one mapping

In a bi-directional one to one mapping, both sides are responsible for managing the relationship and hence both entities must have each other's instances setted to their instance using getters and setters, failing so will end up inserting a null in the db foreign key columns and one could not be able to get other object's details with one object.


For this example we are taking two entities Employee and Info, the mappings and pojo will look something like this:

Employee.java


package com.tbNext.hb.models;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
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;
	
	@OneToOne
	private Info info;

	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 setters including info

	public String toString() {
		return "[ID: " + id + " First Name: " + firstName + " Last Name: "
				+ lastName + " Email: " + email + " Phone: " + phone + "]";
	}

}

Info.java

package com.tbNext.hb.models;

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

@Entity
@Table(name = "TB_INFO")
public class Info {
	
	@Id
	@Column(name = "ID")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	
	@Column(name = "FATHER_NAME")
	private String fatherName;
	
	@Column(name = "MOTHER_NAME")
	private String motherName;
	
	@Column(name = "CITY")
	private String city;

	@OneToOne
	private Employee employee;

	public Info() {
		super();
	}

	public Info(String fatherName, String motherName, String city) {
		super();
		this.fatherName = fatherName;
		this.motherName = motherName;
		this.city = city;
	}

	// getter setters including Employee

}

Ad discussed earlier, while inserting we must have setted each other objects using getters and setters as shown below:

		// create an instance of Employee
		Employee employee = new Employee("Tech", "Burps", "info@tbNext.com",
				"8765234599");

		// create an instance of Info
		Info info = new Info("F Name", "M Name", "City");

		// Being bidirectional we must do this
		employee.setInfo(info);
		info.setEmployee(employee);
In the code above, last two lines are important in case of bidirectional mapping, unless we will end up having a null in db for foreign key columns and hence can not fetch both in any of them.

Implementation

Lets execute and try to insert and fetch entities:

package com.tbNext.java;

import javax.persistence.EntityManager;

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

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

		// create an instance of Employee
		Employee employee = new Employee("Tech", "Burps", "info@tbNext.com",
				"8765234599");

		// create an instance of Info
		Info info = new Info("F Name", "M Name", "City");

		// Being bidirectional we must do this
		employee.setInfo(info);
		info.setEmployee(employee);

		// Adding entities to db
		em.getTransaction().begin();
		em.persist(info);
		em.persist(employee);
		em.getTransaction().commit();

		// try to fetch employee
		Employee emFromDb = em.find(Employee.class, 1l);
		System.out.println("Employee Id: " + emFromDb.getId() + " Info Id: "
				+ emFromDb.getInfo().getId());

		// try to fetch info
		Info infoFromDb = em.find(Info.class, 1l);
		System.out.println("Info Id: " + infoFromDb.getId() + " Employee Id: "
				+ infoFromDb.getEmployee().getId());

	}
}

Output: We can see, there are three insert queries and while trying to fetch we are having associated entities in the object:

Hibernate: insert into TB_INFO (CITY, employee_ID, FATHER_NAME, MOTHER_NAME) values (?, ?, ?, ?)
Hibernate: insert into TB_EMPLOYEE (EMAIL, FIRST_NAME, info_ID, LAST_NAME, PHONE) values (?, ?, ?, ?, ?)
Hibernate: update TB_INFO set CITY=?, employee_ID=?, FATHER_NAME=?, MOTHER_NAME=? where ID=?
Employee Id: 1 Info Id: 1
Info Id: 1 Employee Id: 1

2) Unidirectional one to one mapping


In the above section we have seen, while using bi-directional one to one mapping, the relationship is managed at both ends and hence we have to pass related entity object in both side. In a unidirectional mapping one end is responsible for the relationship and hence we dont need to set it on both ends.

To make unidirectional mapping, one end has to be the owner and other end will be managed by owner side and hence other side will have an annotation @OneToOne (mappedBy ="account")

In this example we will make Employee as owner and Info as mapped to account. Now the annotations will be changed like:

	@OneToOne
	private Info info;

	@OneToOne(mappedBy="info")
	private Employee employee;

Lets see the implementation of unidirectional one to one mapping:

package com.tbNext.java;

import javax.persistence.EntityManager;

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

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

		// create an instance of Employee
		Employee employee = new Employee("Tech", "Burps", "info@tbNext.com",
				"8765234599");

		// create an instance of Info
		Info info = new Info("F Name", "M Name", "City");

		// unidirectional
		employee.setInfo(info);
		//info.setEmployee(employee);

		// Adding entities to db
		em.getTransaction().begin();
		em.persist(info);
		em.persist(employee);
		em.getTransaction().commit();

		// try to fetch employee
		Employee emFromDb = em.find(Employee.class, employee.getId());
		System.out.println("Employee Id: " + emFromDb.getId() + " Info Id: "
				+ emFromDb.getInfo().getId());

		// try to fetch info
		Info infoFromDb = em.find(Info.class, info.getId());
		System.out.println("Info Id: " + infoFromDb.getId());

	}
}


Output: We can see, there are two insert queries and while trying to fetch we are having associated entities in the object:

Hibernate: insert into TB_INFO (CITY, FATHER_NAME, MOTHER_NAME) values (?, ?, ?)
Hibernate: insert into TB_EMPLOYEE (EMAIL, FIRST_NAME, info_ID, LAST_NAME, PHONE) values (?, ?, ?, ?, ?)
Employee Id: 1 Info Id: 1
Info Id: 1

@JoinColumn Annotation in JPA


We have defined one to one mapping using bi-directional and unidirectional, we have used foreign key strategy for doing this. By default a foreign key is created as mappedTableName + _ + mappedTablePrimary key.

@JoinColumn is used to specify user defined foreign key column in owner entity, this have two attributes as:

	@OneToOne
	@JoinColumn(name = "INFO_ID", referencedColumnName = "ID")
	private Info info;

As name identifies the foreignkey column name in Employee and referencedColumnName specifies the reference column name in Info entity.

The good thing about unidirectional one to one mapping is that, this does not create circular dependencies.

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