- Details
- Written by Nam Ha Minh
- Last Updated on 12 December 2023   |   Print Email
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:
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:- Creating Database and Tables
- Creating Maven-Eclipse Project
- Coding Model Classes with Annotations
- Writing Hibernate Configuration File
- Writing a Test Program
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:
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:
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.
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.
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>
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:
Result in the
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:
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on
Facebook and watch
his Java videos you YouTube.