Bidirectional One-To-One Relationship on Foreign Key in Hibernate

In bidirectional association, we will have navigation in both directions, i.e, both side of the association will have the reference to the other side. The both side of the association will implement one of the collection interfaces, if it has the reference to the other entity.

In one to one relationship, one source object can have relationship with only one target object. Let’s consider CD and Artist. So one CD can be written by one Artist or an Artist can write only one CD. So we will create two tables CD and Artist in the database and we will see how one-to-one relationship works step by step.

Now we will apply one-to-one relationship. So only one CD can be written by only one Artist.

In One-To-One relationship on foreign key, CD table has an artistId as foreign key with unique constraint, which is a reference to Artist table.

Step 1. Create tables
Create table – cd

CREATE TABLE `cd` (
  `cdId` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `cdTitle` varchar(50) NOT NULL,
  `artistId` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`cdId`),
  UNIQUE KEY `unique_artist` (`artistId`),
  CONSTRAINT `fk_artist` FOREIGN KEY (`artistId`) REFERENCES `artist` (`artistId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

 
Create table – artist

CREATE TABLE `artist` (
  `artistId` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `artistName` varchar(50) NOT NULL,
  PRIMARY KEY (`artistId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

 

Step 2. Create a java project in any Java based IDE and configure for hibernate jars.

Step 3. Create hibernate reverse engineering and configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd">
<hibernate-reverse-engineering>
  <schema-selection match-catalog="hibernate_assoc"/>
  <table-filter match-name="cd"/>
  <table-filter match-name="artist"/>
</hibernate-reverse-engineering>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <!-- hibernate database specific dialect -->
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <!-- hibernate database specific driver -->
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <!-- hibernate database connection URL -->
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_assoc?zeroDateTimeBehavior=convertToNull</property>
    <!-- hibernate database username -->
    <property name="hibernate.connection.username">root</property>
    <!-- show sql in console -->
    <property name="hibernate.show_sql">true</property>
    <!-- format sql in cosole for better readability -->
    <property name="hibernate.format_sql">true</property>
    <!-- which context to use for sql processing -->
    <property name="hibernate.current_session_context_class">thread</property>
    <!-- translator for HSQL -->
    <property name="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</property>
    <!-- hibernate mapping resources or files -->
    <mapping resource="in/webtuts/hibernate/domain/Artist.hbm.xml"/>
    <mapping resource="in/webtuts/hibernate/domain/Cd.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

 

Step 4. Create hibernate utility class which creates singleton SessionFactory from which Session object will be created.

package in.webtuts.hibernate.utils;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
/**
 * Hibernate Utility class with a convenient method to get Session Factory
 * object.
 *
 * @author admin
 */
public class HibernateUtil {
    private static final SessionFactory sessionFactory;
    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml)
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Log the exception.
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

 

Step 5. Create mapping xml file and POJO for artist table. Look at the xml file, we have <one-to-one /> with property-ref=”artist” which makes sure that one-to-one relationship on foreign key. property-ref declares that the artist property of the Cd class is the inverse of a property on the other side of the association.

<?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="in.webtuts.hibernate.domain.Artist" table="artist" catalog="hibernate_assoc">
        <id name="artistId" type="java.lang.Long">
            <column name="artistId" />
            <generator class="identity" />
        </id>
        <property name="artistName" type="string">
            <column name="artistName" length="50" not-null="true" />
        </property>
        <one-to-one name="cd" class="in.webtuts.hibernate.domain.Cd" property-ref="artist"/>
    </class>
</hibernate-mapping>
package in.webtuts.hibernate.domain;
/**
 * Artist generated by hbm2java
 */
public class Artist implements java.io.Serializable {
    private Long artistId;
    private String artistName;
    private Cd cd;
    public Artist() {
    }
    public Artist(String artistName) {
        this.artistName = artistName;
    }
    public Artist(String artistName, Cd cd) {
        this.artistName = artistName;
        this.cd = cd;
    }
    public Long getArtistId() {
        return this.artistId;
    }
    public void setArtistId(Long artistId) {
        this.artistId = artistId;
    }
    public String getArtistName() {
        return this.artistName;
    }
    public void setArtistName(String artistName) {
        this.artistName = artistName;
    }
    public Cd getCd() {
        return cd;
    }
    public void setCd(Cd cd) {
        this.cd = cd;
    }
}

 

Step 6. Create mapping xml file and POJO for cd table. cascade represents that if the cascade side of the entity is saved then the other side of the entity will automatically saved by the hibernate.

<?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="in.webtuts.hibernate.domain.Cd" table="cd" catalog="hibernate_assoc">
        <id name="cdId" type="java.lang.Long">
            <column name="cdId" />
            <generator class="identity" />
        </id>
        <!-- many-to-one relationship with column name="artistId" with unique="true" which makes sure one-to-one relationship -->
        <many-to-one name="artist" class="in.webtuts.hibernate.domain.Artist" fetch="select" cascade="all">
            <column name="artistId" not-null="true" unique="true" />
        </many-to-one>
        <property name="cdTitle" type="string">
            <column name="cdTitle" length="50" not-null="true" />
        </property>
    </class>
</hibernate-mapping>
package in.webtuts.hibernate.domain;
/**
 * Cd generated by hbm2java
 */
public class Cd implements java.io.Serializable {
    private Long cdId;
    private Artist artist;
    private String cdTitle;
    public Cd() {
    }
    public Cd(Artist artist, String cdTitle) {
        this.artist = artist;
        this.cdTitle = cdTitle;
    }
    public Long getCdId() {
        return this.cdId;
    }
    public void setCdId(Long cdId) {
        this.cdId = cdId;
    }
    public Artist getArtist() {
        return this.artist;
    }
    public void setArtist(Artist artist) {
        this.artist = artist;
    }
    public String getCdTitle() {
        return this.cdTitle;
    }
    public void setCdTitle(String cdTitle) {
        this.cdTitle = cdTitle;
    }
}

 
Step 7. Now we will create a main class for testing one-to-one on foreign key.

package in.webtuts.hibernate.test;
import in.webtuts.hibernate.domain.Artist;
import in.webtuts.hibernate.domain.Cd;
import in.webtuts.hibernate.utils.HibernateUtil;
import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.Transaction;
/**
 *
 * @author https://roytuts.com
 */
public class OneToOneTest {
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Session session = null;
        Transaction transaction = null;
        try {
            Artist artist = new Artist();
            artist.setArtistName("Soumitra");
            Cd cd1 = new Cd();
            cd1.setCdTitle("Java");
            cd1.setArtist(artist);
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            Serializable cdId = session.save(cd1);
            System.out.println("From CD : Save");
            Cd cd = (Cd) session.load(Cd.class, cdId);
            System.out.println("Cd ID: " + cd.getCdId());
            System.out.println("Cd Title: " + cd.getCdTitle());
            System.out.println("Artist ID: " + cd.getArtist().getArtistId());
            System.out.println("Artist Name: " + cd.getArtist().getArtistName());
            System.out.println();
            System.out.println("From Artist : Load");
            Artist a = (Artist) session.load(Artist.class, cd.getArtist().getArtistId());
            System.out.println("Artist ID: " + a.getArtistId());
            System.out.println("Artist Name: " + a.getArtistName());
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        }
    }
}

 
Step 8. Run the main class and see the output as shown below. While we save value for cd, the below values are stored into the database tables.
inserted data into artist table

insert  into `artist`(`artistId`,`artistName`) values (1,'Soumitra');

 
inserted data into cd table

insert  into `cd`(`cdId`,`cdTitle`,`artistId`) values (1,'Java',1);

 
Output

Hibernate:
    insert
    into
        hibernate_assoc.artist
        (artistName)
    values
        (?)
Hibernate:
    insert
    into
        hibernate_assoc.cd
        (artistId, cdTitle)
    values
        (?, ?)
From CD : Save
Cd ID: 1
Cd Title: Java
Artist ID: 1
Artist Name: Soumitra
From Artist : Load
Artist ID: 1
Artist Name: Soumitra

 
That’s all. Thanks for your reading.

Leave a Reply

Your email address will not be published. Required fields are marked *