Hibernate One-To-One Unidirectional with Shared Primary Key (Annotation)

In this tutorial, we will learn about how to use Hibernate One-To-One Unidirectional Shared primary key mapping.

In One-To-One Unidirectional Shared primary key mapping, two tables share the same primary key.
The Unidirectional relationship means only one side navigation is possible.(STUDENT to ADDRESS in this example)

OneToOneUniSharedPrimaryKey_img1


We are discussing an example of Student and Address relationship. A student lives on one Address. And one address can be occupied by only one student.


Following technologies being used:

  • Hibernate 4.3.6.Final
  • MySQL Server 5.6
  • Maven 3.1.1
  • JDK 1.6
  • Eclipse JUNO Service Release 2

Let’s begin.

Step 1: Create required Database Table

Open MySQL terminal / workbench terminal and execute following MySQL script :

create table STUDENT (
   student_id BIGINT NOT NULL AUTO_INCREMENT,
   first_name VARCHAR(30) NOT NULL,
   last_name  VARCHAR(30) NOT NULL,
   section    VARCHAR(30) NOT NULL,
   PRIMARY KEY (student_id)
);


create table ADDRESS (
   address_id BIGINT NOT NULL,
   street VARCHAR(30) NOT NULL,
   city  VARCHAR(30) NOT NULL,
   country  VARCHAR(30) NOT NULL,
   PRIMARY KEY (address_id),
   CONSTRAINT student_address FOREIGN KEY (address_id) REFERENCES STUDENT ( student_id) ON DELETE CASCADE 
);

Here we have created Student and Address tables. Student table is pretty obvious. But while creating Address table, we have also specified a foreign key constraint from Address table primary key to Student table primary key.Have a look on table schema figure above.

Please visit MySQL installation on Local PC in case you are finding difficulties in setting up MySQL locally.

Step 2: Create project directory structure

Following will be the final project structure:

OneToOneUniSharedPrimaryKey_img2

Now let’s add/update the content mentioned in above project structure.

Step 3: Update pom.xml to include required Hibernate and MySQL dependency

Following is the updated minimalistic pom.xml

<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>com.websystique.hibernate</groupId>
	<artifactId>OneToOneUniSharedPrimaryKey</artifactId>
	<version>1.0.0</version>
	<packaging>jar</packaging>

	<name>OneToOneUniSharedPrimaryKey</name>

	<properties>
		<hibernate.version>4.3.6.Final</hibernate.version>
		<mysql.connector.version>5.1.31</mysql.connector.version>
	</properties>

	<dependencies>
		<!-- Hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<!-- MySQL -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.connector.version}</version>
		</dependency>
	</dependencies>
	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.2</version>
					<configuration>
						<source>1.6</source>
						<target>1.6</target>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

</project>

On saving pom.xml with above content, Eclipse will download all the dependencies.

Step 4: Create Model classes

Model class Student & Address are simple POJO class which is annotated with JPA annotations to map it to a database tables(created in step 1).

package com.websystique.hibernate.model;

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 = "STUDENT")
public class Student {

	@Id
	@GeneratedValue
	@Column(name = "STUDENT_ID")
	private long id;

	@Column(name = "FIRST_NAME")
	private String firstName;

	@Column(name = "LAST_NAME")
	private String lastName;

	@Column(name = "SECTION")
	private String section;

	@OneToOne(cascade = CascadeType.ALL)
	@PrimaryKeyJoinColumn
	private Address address;

	public Student() {

	}

	public Student(String firstName, String lastName, String section) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.section = section;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getSection() {
		return section;
	}

	public void setSection(String section) {
		this.section = section;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", firstName=" + firstName + ", lastName="
				+ lastName + ", section=" + section + ", address=" + address
				+ "]";
	}

}

package com.websystique.hibernate.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "ADDRESS")
public class Address {

	@Id
	@Column(name = "ADDRESS_ID")
	private long id;

	@Column(name = "STREET")
	private String street;

	@Column(name = "CITY")
	private String city;

	@Column(name = "COUNTRY")
	private String country;

	public Address() {

	}

	public Address(String street, String city, String country) {
		this.street = street;
		this.city = city;
		this.country = country;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getStreet() {
		return street;
	}

	public void setStreet(String street) {
		this.street = street;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	@Override
	public String toString() {
		return "Address [id=" + id + ", street=" + street + ", city=" + city
				+ ", country=" + country + "]";
	}
	
}

@OneToOne on address property of Student class indicates that there is a one-to-one association from Student to Address.PrimaryKeyJoinColumn indicates that the primary key of the Student entity is used as a foreign key to the Address entity.Together these two annotation indicates that both the source and target share the same primary key values.Also note the use of cascade = CascadeType.ALL.Since Address entity can not exist without Student entity, with this cascade setting, address entity will be updated/deleted on subsequent update/delete on student entity.Note that Address class does not contain any reference to Student, as it is a unidirectional relationship(From Student to Address).

Step 5: Create Hibernate configuration file

We need to inform hibernate about how to connect to database, which database dialect we will be using so that hibernate can generate the instruction specific to that database.

We define all these information in hibernate.cfg.xml. Create this file with below content and save it in src/main/resources folder.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">


<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.username">myuser</property>
        <property name="hibernate.connection.password">mypassword</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/websystique</property>
        <property name="show_sql">true</property>
        <property name="format_sql">false</property>
        <mapping class="com.websystique.hibernate.model.Student"/>
        <mapping class="com.websystique.hibernate.model.Address"/>
    </session-factory>
</hibernate-configuration>

dialect property informs hibernate to generate database specific (MySQL here) instructions. driver_class defines the database specific driver hibernate will use to make connection. next 3 properties corresponds to database connection. show_sql will instruct hibernate to log all the statements on console and format_sql instructs it to display properly formatted sql. mapping tag instructs hibernate to perform mapping for classes refereed by class attribute.

Step 6: Create Hibernate Utility class

This class is well-known in hibernate community, and used for configuring hibernate on startup and managing session factory.

package com.websystique.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtil {
	
	private static final SessionFactory sessionFactory;
	
	static{
		try{
			sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();

		}catch (Throwable ex) {
			System.err.println("Session Factory could not be created." + ex);
			throw new ExceptionInInitializerError(ex);
		}	
	}
	
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	
}

Step 7: Create executable class to Run and perform operations on Database

package com.websystique.hibernate;

import java.util.List;

import org.hibernate.Session;

import com.websystique.hibernate.model.Address;
import com.websystique.hibernate.model.Student;

public class HibernateStandAlone {
	
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {

		Student student = new Student("Sam","Disilva","Maths");
		Address address = new Address("10 Silver street","NYC","USA");
		
		
		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();

		session.persist(student);
		
		address.setId(student.getId());
		student.setAddress(address);
		session.save(student);
		
		List<Student> students = (List<Student>)session.createQuery("from Student ").list();
		for(Student s: students){
			System.out.println("Details : "+s);
		}
		
		session.getTransaction().commit();
		session.close();  
	}

}

Look at how we have first persisted Student class , so that it’s id can be generated. Then we have set the address id with student id(so that foreign key constraint can be respected).Finally we have set the address property of Student and saved student.Thanks to Cascade attribute on address property of Student class, address will be saved automatically on student save.No need to save the address explicitly.

Execute above class as Java application. You will see following output

Hibernate: insert into STUDENT (FIRST_NAME, LAST_NAME, SECTION) values (?, ?, ?)
Hibernate: select address_.ADDRESS_ID, address_.CITY as CITY2_0_, address_.COUNTRY as COUNTRY3_0_, address_.STREET as STREET4_0_ from ADDRESS address_ where address_.ADDRESS_ID=?
Hibernate: select student0_.STUDENT_ID as STUDENT_1_1_, student0_.FIRST_NAME as FIRST_NA2_1_, student0_.LAST_NAME as LAST_NAM3_1_, student0_.SECTION as SECTION4_1_ from STUDENT student0_
Details : Student [id=1, firstName=Sam, lastName=Disilva, section=Maths, address=Address [id=1, street=10 Silver street, city=NYC, country=USA]]
Hibernate: insert into ADDRESS (CITY, COUNTRY, STREET, ADDRESS_ID) values (?, ?, ?, ?)

Below is the snapshot of MySQL database after execution of above program.

OneToOneUniSharedPrimaryKey_img3

OneToOneUniSharedPrimaryKey_img4
That’s it.

Download Source Code



References

If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help me improve further our learning process.

If you appreciate the effort I have put in this learning site, help me improve the visibility of this site towards global audience by sharing and linking this site from within and beyond your network. You & your friends can always link my site from your site on www.websystique.com, and share the learning.

After all, we are here to learn together, aren’t we?

  • Pingback: Hibernate Entity OneToOne with same Primary and Foreign Key | Solutions for enthusiast and professional programmers()

  • Pingback: Hibernate Many-To-Many Bidirectional (Annotation) - WebSystique()

  • Kingshore Naidu

    Could please give a example of how update

    • websystique

      Hi Naidu,

      Look at this & this post to learn about update with Hibernate. Any issue, let me know.

      • Kingshore Naidu

        Thanks for replay,

        After some time i done like bellow,…

        public boolean update(int id, Student student, Address address) {

        boolean result = false;

        try{

        Session session = HibernateUtil.getSessionFactory().openSession();

        session.beginTransaction();

        address.setId(id);

        student.setAddress(address);

        student.setId(id);

        session.update(student);

        result = true;

        session.getTransaction().commit();

        session.close();

        }catch(Exception e){

        }
        return result;
        }

        Can you help out for bellow code.(save record)

        public int saveStudent(Student student, Address address) {

        session = HibernateUtil.getSessionFactory().openSession();

        session.beginTransaction();

        session.persist(student);

        address.setId(student.getId());

        student.setAddress(address);

        int i = (Integer) session.save(student);

        session.getTransaction().commit();

        session.close();

        return i;

        }

        • websystique

          Hi Naidu,
          What problem exactly are you getting here? I see you have written both save & update logic now, should be fine. I misunderstood something?

          • Kingshore Naidu

            Hi,
            i wrote int i = (Integer) session.save(student); here i am getting typecasting error. Because the save(obj) return type is Serializable. it means its return object reference value so changed that line as

            long i = (Long) session.save(student);

            now it working fine …. Let me know if i am mistake….
            Thanks …

          • Venkat

            Hi Websystique, I’m practicing the exactly same code above. But every time i’m getting the same error that

            1) Exception in thread “main” org.hibernate.exception.SQLGrammarException: could not extract ResultSet

            2) Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column ‘student0_.id’ in ‘field list’

          • websystique

            Hi Venkat,

            Are you using the same code as shown in this post, specially, the id property of Student class? In the post code, id is referring to STUDENT_ID which is a column in STUDENT table in database. There is no ID column in STUDENT table in database. From the error it seems that hibernate is trying to find a property id on STUDENT.

            @Id
            @GeneratedValue
            @Column(name = “STUDENT_ID”)
            private long id;

  • Pingback: Hibernate Many-To-Many Unidirectional ( Annotation) - WebSystique()

  • Pingback: Hibernate Many-To-One Bidirectional (Annotation) - WebSystique()

  • Pingback: Hibernate Many-To-One Unidirectional (Annotation) - WebSystique()

  • Pingback: Hibernate One-To-One Bidirectional with Shared Primary Key (Annotation) - WebSystique()

  • Pingback: Hibernate One-To-One Unidirectional with Foreign Key Associations (Annotation) - WebSystique()