Hibernate One to One Unidirectional Foreign Key
In this tutorial, we show you how to configure a Hibernate One-to-One Unidirectional Association with Foreign keys using either annotations or xml mapping files.
- A one-to-one mapping means that one object can have only one relation – at most.
- In a foreign key association, one table has a foreign key column that references the primary key of the associated table.
- A unidirectional relationship means that only one side (the owning side) is able to navigate to the relationship. In the following example only the dog can retrieve the collar reference and not vice versa.
Maven Dependencies
We use Apache Maven to manage the projects dependencies. Add the following dependencies to your projects pom.xml
file.
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.4</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.3.Final</version>
</dependency>
Create Model Classes + Annotation Mappings
Following classes are simple POJOs, annotated with standard Java Persistence Api (JPA) annotations. These annotations are the mapping between the Java Class and the corresponding Database Tables. The first POJO is the Dog
class.
package com.memorynotfound.hibernate;
import javax.persistence.*;
@Entity
@Table(name = "TBL_DOG")
public class Dog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "DOG_ID")
private Integer id;
@Column(name = "NAME")
private String name;
@JoinColumn(name = "COLLAR_ID", unique = true)
@OneToOne(cascade = CascadeType.ALL)
private Collar collar;
public Dog() {
}
public Dog(String name, Collar collar) {
this.name = name;
this.collar = collar;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collar getCollar() {
return collar;
}
public void setCollar(Collar collar) {
this.collar = collar;
}
@Override
public String toString() {
return "Dog{" +
"id=" + id +
", name='" + name + '\'' +
", collar=" + collar +
'}';
}
}
The second POJO is the Collar
class.
package com.memorynotfound.hibernate;
import javax.persistence.*;
@Entity
@Table(name = "TBL_COLLAR")
public class Collar {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "COLLAR_ID")
private Integer id;
@Column(name = "COLOR")
private String color;
public Collar() {
}
public Collar(String color) {
this.color = color;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Collar{" +
"id=" + id +
", color='" + color + '\'' +
'}';
}
}
Hibernate HBM XML Mapping
If you prefer Hibernate XML HBM Mapping files over Annotations, you can use the equivalent hibernate xml mapping for the Dog
class. This file is located in the src/main/resources
folder and is named Dog.hbm.xml
. Note: in order to map the foreing key, we need a many-to-one
relationship here.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.memorynotfound.hibernate.Dog" table="TBL_DOG">
<id name="id" type="java.lang.Integer" column="DOG_ID">
<generator class="identity" />
</id>
<property name="name" column="NAME"/>
<many-to-one name="collar" cascade="all"
column="COLLAR_ID" unique="true"/>
</class>
</hibernate-mapping>
And the equivalent hibernate xml mapping for the Collar
class. This file is located in the src/main/resources
folder and is named Collar.hbm.xml
.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.memorynotfound.hibernate.Collar" table="TBL_COLLAR">
<id name="id" type="java.lang.Integer" column="COLLAR_ID">
<generator class="identity" />
</id>
<property name="color" column="COLOR"/>
</class>
</hibernate-mapping>
Configure Hibernate Connection Properties
We can configure the database properties using the hibernate hibernate.cfg.xml
file, located on the classpath in the src/main/resources
folder.
<?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 properties -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/dogstore?serverTimezone=Europe/Brussels</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- show mysql queries output in console -->
<property name="hibernate.show_sql">true</property>
<!-- manage automatic database creation -->
<property name="hibernate.hbm2ddl.auto">create-drop</property>
<!-- add annotated resources here -->
<mapping class="com.memorynotfound.hibernate.Collar"/>
<mapping class="com.memorynotfound.hibernate.Dog"/>
</session-factory>
</hibernate-configuration>
HibernateUtil
This class is used to configure hibernate during startup and create a standalone SessionFactory
.
package com.memorynotfound.hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() throws HibernateException {
return sessionFactory.openSession();
}
public static void shutdown() {
sessionFactory.close();
}
}
Create app
Finally, we can test the application. We create a new Dog
object and associate a Collar
object. Afterwards, we save the object and commit the transaction.
package com.memorynotfound.hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import java.util.Arrays;
import java.util.List;
public class App {
public static void main (String...args){
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
Collar favoriteCollar = new Collar("spiked-collar");
Dog pluto = new Dog("pluto", favoriteCollar);
session.save(pluto);
tx.commit();
List dogs = (List)session.createQuery("from Dog").list();
System.out.println("Dogs: " + Arrays.toString(dogs.toArray()));
session.close();
HibernateUtil.shutdown();
}
}
The previous application prints the following info to the console.
...
Hibernate: insert into TBL_COLLAR (COLOR) values (?)
Hibernate: insert into TBL_DOG (COLLAR_ID, NAME) values (?, ?)
Hibernate: select dog0_.DOG_ID as DOG_ID1_1_, dog0_.COLLAR_ID as COLLAR_I3_1_, dog0_.NAME as NAME2_1_ from TBL_DOG dog0_
Dogs: [Dog{id=1, name='pluto', collar=Collar{id=1, color='spiked-collar'}}]
...