In this Hibernate tutorial series, we are going to show you how to implement a bidirectional one-to-one association using JPA and Hibernate annotations. The annotations approach is preferred as an alternative to XML descriptor which is described in the tutorial Hibernate One-to-One With Primary Key XML Mapping Example. Let’s recall about the bidirectional one-to-one association by looking at the following entity relationship diagram:

 

one-to-one with primary key entity relationship diagram

As we can see, these two tables share a same primary key (product_id) so that it’s possible to navigate to a corresponding product_detail from a product and vice-versa, thus this is called bidirectional (two-ways) association on primary key.

In this tutorial, we will be developing a sample Hibernate program to manage the above product - product_detail association using the following pieces of software (of course you can use newer versions):

The software versions here are the latest as of this writing, but using similar versions is also possible. Here are the steps we should follow:

Table of content:

  1. Creating Database and Tables
  2. Creating Maven-Eclipse Project
  3. Coding Model Classes with Annotations
  4. Writing Hibernate Configuration File
  5. Writing a Test Program
 

1. Creating Database and Tables

Let’s create a database called productsdb containing two tables product and product_detail by executing the following MySQL script:

create database productsdb;
use productsdb;

CREATE TABLE `product` (
  `product_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `description` varchar(512) NOT NULL,
  `price` float NOT NULL,
  PRIMARY KEY (`product_id`)
);

CREATE TABLE `product_detail` (
  `product_id` int(11) NOT NULL,
  `part_number` varchar(45) NOT NULL,
  `dimension` varchar(45) NOT NULL,
  `weight` float NOT NULL,
  `manufacturer` varchar(45) NOT NULL,
  `origin` varchar(45) NOT NULL,
  PRIMARY KEY (`product_id`)
);


 We would have the following database structure:

productsdb database structure


2. Creating Maven-Eclipse Project

Eclipse Kepler has Maven integration by default, so creating a Maven project is quick and easy. Let’s create a Maven project with the following structure:

Hibernate one-to-one primary key annotations project structure

The project HibernateOne2OnePrimaryKeyAnnotationsExample consists of the following files:

  • Model classes: Product.java and ProductDetail.java
  • Hibernate XML configuration file: hibernate.cfg.xml
  • Test program: ProductsManager.java
  • Maven project: pom.xml
We specify two primary dependencies of hibernate-core and mysql-connector-java in the pom.xml file as follows:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
		http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.codejava.hibernate</groupId>
  <artifactId>HibernateOne2OnePrimaryKeyAnnotationsExample</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
  	<dependency>
  		<groupId>org.hibernate</groupId>
  		<artifactId>hibernate-core</artifactId>
  		<version>4.2.7.SP1</version>
  	</dependency>
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>5.1.26</version>
  	</dependency>
  </dependencies>  
</project>
The other related dependencies will be resolved automatically by Maven.


3. Coding Model Classes with Annotations

Create two model classes called Product.java and ProductDetail.java with the following source code:

File net\codejava\hibernate\Product.java:

package net.codejava.hibernate;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

@Entity
@Table(name = "PRODUCT")
public class Product {
	private long productId;
	private String name;
	private String description;
	private float price;
	private ProductDetail productDetail;

	public Product() {
	}

	@Id
	@GeneratedValue
	@Column(name = "PRODUCT_ID")
	public long getProductId() {
		return productId;
	}

	@OneToOne(cascade = CascadeType.ALL)
	@PrimaryKeyJoinColumn
	public ProductDetail getProductDetail() {
		return productDetail;
	}

	// other getters and setters
}
 

File net\codejava\hibernate\ProductDetail.java:

package net.codejava.hibernate;

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

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@Table(name = "PRODUCT_DETAIL")
public class ProductDetail {
	private long productId;
	private String partNumber;
	private String dimension;
	private float weight;
	private String manufacturer;
	private String origin;
	private Product product;

	public ProductDetail() {
	}

	@Id
	@GeneratedValue(generator = "foreigngen")
	@GenericGenerator(strategy = "foreign", name="foreigngen",
			parameters = @Parameter(name = "property", value="product"))
	@Column(name = "PRODUCT_ID")
	public long getProductId() {
		return productId;
	}


	@Column(name = "PART_NUMBER")
	public String getPartNumber() {
		return partNumber;
	}

	@OneToOne(mappedBy = "productDetail")
	public Product getProduct() {
		return product;
	}

	// other getters and setters
}
Here, we use several annotations as you notice: The @Entity, @Table and @Column annotations are straightforward to understand. The others need some further explanations:

  • @Id and @GeneratedValue: are used in conjunction to map a field as the primary key of the table. Typically, the primary key’s values are auto-generated.
  • On the Product side, we use the @OneToOne and @PrimaryKeyJoinColumn annotations to tell Hibernate creates a one-to-one association with the ProductDetail and the join column is the primary key column.
  • On the ProductDetail side, we need to use the @GenericGenerator to specify a foreign key strategy in order to generate values for the product_id column as a foreign key. And the @OneToOne annotation tells Hibernate that the product field is a one-to-one association which is mapped by this productDetail.


4. Writing Hibernate Configuration File

We need to write XML descriptor in the hibernate.cfg.xml file to tell Hibernate which database to connect:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>        
  <session-factory>
    <!-- Database connection settings -->
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost:3306/productsdb</property>
    <property name="connection.username">root</property>
    <property name="connection.password">secret</property>
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    
    <mapping class="net.codejava.hibernate.Product"/>
    <mapping class="net.codejava.hibernate.ProductDetail"/>
      
  </session-factory>
</hibernate-configuration>
 

5. Writing a Test Program

Write code for the test program (ProductsManager.java) as follows:

package net.codejava.hibernate;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

/**
 * This program demonstrates using Hibernate framework to manage a
 * bidirectional one-to-one association on a primary key using 
 * annotations.
 * @author www.codejava.net
 *
 */
public class ProductsManager {

	public static void main(String[] args) {
		// loads configuration and mappings
		Configuration configuration = new Configuration().configure();
		ServiceRegistryBuilder registry = new ServiceRegistryBuilder();
		registry.applySettings(configuration.getProperties());
		ServiceRegistry serviceRegistry = registry.buildServiceRegistry();
		
		// builds a session factory from the service registry
		SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
		
		// obtains the session
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		
		// creates a new product
		Product product = new Product();
		product.setName("Civic");
		product.setDescription("Comfortable, fuel-saving car");
		product.setPrice(20000);
		
		// creates product detail
		ProductDetail detail = new ProductDetail();
		detail.setPartNumber("ABCDEFGHIJKL");
		detail.setDimension("2,5m x 1,4m x 1,2m");
		detail.setWeight(1000);
		detail.setManufacturer("Honda Automobile");
		detail.setOrigin("Japan");
		
		// sets the bi-directional association
		product.setProductDetail(detail);
		detail.setProduct(product);
		
		// persists the product
		session.save(product);
		
		// queries all products
		List<Product> listProducts = session.createQuery("from Product").list();
		for (Product aProd : listProducts) {
			String info = "Product: " + aProd.getName() + "\n";
			info += "\tDescription: " + aProd.getDescription() + "\n";
			info += "\tPrice: $" + aProd.getPrice() + "\n";
			
			ProductDetail aDetail = aProd.getProductDetail();
			info += "\tPart number: " + aDetail.getPartNumber() + "\n";
			info += "\tDimension: " + aDetail.getDimension() + "\n";
			info += "\tWeight: " + aDetail.getWeight() + "\n";
			info += "\tManufacturer: " + aDetail.getManufacturer() + "\n";
			info += "\tOrigin: " + aDetail.getOrigin() + "\n";
			
			System.out.println(info);
		}
		
		session.getTransaction().commit();
		session.close();
	}

}
Output of the program:

Hibernate: insert into PRODUCT (description, name, price) values (?, ?, ?)
Hibernate: insert into PRODUCT_DETAIL (dimension,...) values (?, ?, ?, ?, ?, ?)
Hibernate: select product0_.PRODUCT_ID ... from PRODUCT product0_
Product: Civic
	Description: Comfortable, fuel-saving car
	Price: $20000.0
	Part number: ABCDEFGHIJKL
	Dimension: 2,5m x 1,4m x 1,2m
	Weight: 1000.0
	Manufacturer: Honda Automobile
	Origin: Japan
Result in the product table:

records in product table

Result in the product_detail table:

records in product detail table

You can download the sample project attached below, or check the code examples on GitHub here.

 

Related Hibernate One-to-OneTutorials:

 

Other Hibernate Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (HibernateOne2OnePrimaryKeyAnnotationsExample.zip)HibernateOne2OnePrimaryKeyAnnotationsExample.zip[Eclipse-Maven project]17 kB

Add comment

   


Comments 

#2Nam2020-03-30 23:29
Hi Nikhil,
You need to create a sequence in your Oracle database. See the guide in this tutorial: codejava.net/.../...
Quote
#1Nikhil2020-03-30 10:16
Hi Nam,
I am getting this error
Table 'productsdb.hibernate_sequence' doesn't exist
Please help
Thanks
Quote