One to One Hibernate/JPA Example

In this tutorial we will demonstrate how to set up Hibernate One-to-One Mapping between two Database tables. We will show how to create and deploy four applications using different approaches to set up the Object relationship.

Overview of One to One relationship

In JPA terms,  a One to One relationship is where a source object has an attribute that references an attribute available in another object. As an example, we will use a Customer table which is in relation with the CustomerInfo Table:

hibernate one to one

In a One to One relationship, each row in one database table is linked to 1 and only 1 other row in another table. So, in a one-to-one relationship between Worker and Info, each row in Worker Table is linked to another row in Info Table. The number of rows in Worker Table must thus be equal to the number of rows in Info Table.

What are the benefits of a One to One link ? Apparently this relationship does not really bring any design benefits: however supposing that the Info table contains lots of fields, most of which are seldom retrieved with a query, then introducing a One-To-One mapping would reduce the overhead of retrieving a large number of fields.

To map a One to One relationship you can use the @OneToOne annotation. There are multiple ways to set up the association between the two Objects:

  • One To One bidirectional association between objects
  • One To One unidirectional association between objects
  • Primary Key as Join Column
  • Using MapsId

Let’s see all available options in detail – for the impatient reader we can anticipate that the preferred option, since JPA 2.0 is use MapsId.

One To One bidirectional association between objects

When using a bidirectional association, both Objects declare explicitly the @OneToOne relation:

@Entity(name = "Customer")
public class Customer  {


	@Id
	@GeneratedValue
	private Long id;

	@OneToOne(
			mappedBy = "customer",
			cascade = CascadeType.ALL,
			orphanRemoval = true
		)
	private CustomerInfo info;
	
	private String registrationNumber;

    // getters/setters omitted for brevity
}

And here is the CustomerInfo Class:

@Entity(name = "CustomerInfo")
public  class CustomerInfo  {

	@Id
	@GeneratedValue
	private Long id;

	private String name;

	private String address;

	@OneToOne()
	@JoinColumn(name = "customer_id")
	private Customer customer;

    
   // getters/setters omitted for brevity
}

As you can see, you need also to declare the column in the targeted entity that we use to join the Tables. For this purpose, you can use the @JoinColumn annotation which will reference the Primary Key of the other object.

You can Test the above relation with the following EJB Class:

@Stateless

public class ServiceBean {

	@PersistenceContext
	private EntityManager em;

	public String create() {
		Customer customer = new Customer(UUID.randomUUID().toString());

		CustomerInfo info = new CustomerInfo();
		info.setName("John Smith");
		info.setAddress("15th Avenue New York");
		info.setCustomer(customer);
		em.persist(customer);
		em.persist(info);
		return "Created!";
	}

	public List<CustomerInfo> findAll() {

		Query query = em.createQuery("FROM CustomerInfo");
		List<CustomerInfo> list = query.getResultList();
		return list;

	}

}

You can find the source code for this example on GitHub: https://github.com/fmarchioni/mastertheboss/tree/master/hibernate/OneToOneBidirectional

One To One unidirectional association between objects

When using Unidirectional association, the OneToOne relation is explicit only in one of the two Objects. Here is the Customer Class:

@Entity(name = "Customer")
public class Customer  {


	@Id
	@GeneratedValue
	private Long id;

	@OneToOne
	@JoinColumn(name = "customerInfo_id")
	private CustomerInfo info;
	
       private String registrationNumber;

	// getters/setters omitted for brevity 

}

As you can see, the Class which declared the Relation also includes the JoinColumn to reference the Foreign Key available in the other Table.

The CustomerInfo, therefore, is a plain Entity with no references to the other Class:

@Entity(name = "CustomerInfo")
public   class CustomerInfo  {

	@Id
	@GeneratedValue
	private Long id;

	private String name;

	private String address;

    // getters/setters omitted for brevity 

 
}

The source code for this example is available here: https://github.com/fmarchioni/mastertheboss/tree/master/hibernate/OneToOneUnidirectional

Primary Key as Join Column

When using this approach, we use the Primary Key columns of each table as the join columns. This requires to use both the @OneToOne annotation and the @PrimaryKeyJoinColumn annotation in one of the two objects.

Here is the Customer Class, which does not contain any reference to the CustomerInfo:

@Entity(name = "Customer")
public class Customer  {

	@Id
	private Long id;

       private String registrationNumber;

	// getters/setters omitted for brevity 

}

On the other hand, this is the CustomerInfo Class which is dependent on the Customer object:

@Entity(name = "CustomerInfo")
public   class CustomerInfo  {

	@Id
	private Long id;

	private String name;

	private String address;

	@OneToOne
	@PrimaryKeyJoinColumn
	private Customer customer;

	// getters/setters omitted for brevity 
 
}

Source code for this example available here: https://github.com/fmarchioni/mastertheboss/tree/master/hibernate/OneToOnePrimaryKeyJoinColumn

Using MapsId

The use of primary key join columns for one-to-one primary key associations is available since JPA 1.0.
In JPA 2.0 and newer, the option to use id and maps-id is now available and it is the preferred method going forward.

The problem with the Unidirectional and Bidirectional association is that the ORM engine will fetch the Child entity in a query. Therefore, due to EAGER fetching, each query will require two select statements.

More details about EAGER/LAZY fetching performance are available in this article: Hibernate fetching performance tuning

On the other hand, when using MapsId, the ORM engine assumes both the source and target share the same primary key values.

Here is the Customer Class:

@Entity(name = "Customer")
public class Customer  {

	@Id
	@GeneratedValue
	private Long id;

	private String registrationNumber;

	// getters/setters omitted for brevity 

}

On the other hand, here is the CustomerInfo Class:

@Entity(name = "CustomerInfo")
public   class CustomerInfo  {

	@Id
	private Long id;

	private String name;


	private String address;

	@OneToOne
	@MapsId
	private Customer customer;

   // getters/setters omitted for brevity 
 
}

You will notice that the target Class includes the @MapsId and the @OneToOne annotation. Also the @Id column no longer includes a @GeneratedValue annotation since the identifier is populated with the identifier of the target association.

The source code for this example is available here: https://github.com/fmarchioni/mastertheboss/tree/master/hibernate/OneToOneMapsId

Found the article helpful? if so please follow us on Socials