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.
hibernate-one-to-one-unidirectional-relation

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'}}]
...

Records inserted in the database

hibernate-one-to-one-unidirectional-foreign-key-example-collar hibernate-one-to-one-unidirectional-foreign-key-example-dog

References

Download

You may also like...