Hibernate One-to-One Association on Primary Key Annotations Example
- 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):
- Hibernate 4.2.7.SP1
- JDK 7
- Eclipse IDE 4.3 (Kepler)
- Maven 3
- MySQL Community Server 5.5.23
- MySQL Connector Java driver 5.1.26
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
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:
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:
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:
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:
- Hibernate One-to-One Mapping with Foreign Key Annotations Example
- Hibernate One-to-One With Foreign Key XML Mapping Example
- Hibernate One-to-One With Primary Key XML Mapping Example
Other Hibernate Tutorials:
- Java Hibernate JPA Annotations Tutorial for Beginners
- Hibernate Hello World Tutorial for Beginners with Eclipse and MySQL
- Hibernate One-to-Many Using Join Table XML Mapping Example
- Hibernate Many-to-Many Association with Extra Columns in Join Table Example
- Hibernate Enum Type Mapping Example
- Hibernate Binary Data and BLOB Mapping Example
- Hibernate Query Language (HQL) Example
- Java Hibernate Reverse Engineering Tutorial with Eclipse and MySQL
- Hibernate Basics - 3 ways to delete an entity from the datastore
Comments
You need to create a sequence in your Oracle database. See the guide in this tutorial: codejava.net/.../...
I am getting this error
Table 'productsdb.hibernate_sequence' doesn't exist
Please help
Thanks