One To One Relationship
A one-to-one relationships occurs when one entity is related to exactly one occurrence in another entity. Consider the following relationship:According to the relationship each STUDENT should have a unique STUDENT_ADDRESS. Hence we will need two tables namely STUDENT and STUDENT_ADDRESS to create this relation. In Hibernate, one-to-one relationship between entities can be created by 3 different techniques. In each technique though @OneToOne annotation has to be used. These techniques are:
Using shared primary key
In this technique, hibernate will ensure that it will use a common primary key value in both the tables. This way primary key of entity STUDENT can safely be assumed the primary key of entity STUDENT_ADDRESS also. The example demonstrated in this post is using shared primary key.Using foreign key association
In this association, a foreign key column is created in the owner entity. For example, if we make STUDENT as owner entity, then a extra column “ADDRESS_ID” will be created in STUDENT table. This column will store the foreign key for STUDENT_ADDRESS table.Using a common join table
In this association, the join table will have two foreign key columns (i.e) it will have both the primary key columns from the two entity tables (for example STUDENT_ID and ADDRESS_ID from STUDENT and STUDENT_ADDRESS entity tables respectively). One of the foreign keys will serve as the primary key for the join table. An unique constraint will be applied on the remaining foreign key column and hence both the foreign key columns will not have the duplicate values.Creating Database
Before we start lets create a simple database and table to apply hibernate operations on. Copy and Paste the following sql query in your query editor and execute.CREATE table STUDENT (student_id bigint identity NOT NULL PRIMARY KEY, rollno varchar(20), firstname varchar(50), lastname varchar(50), course varchar(50)) CREATE TABLE STUDENT_ADDRESS (student_id bigint NOT NULL PRIMARY KEY FOREIGN KEY REFERENCES STUDENT (student_id), address varchar(100) DEFAULT NULL, city varchar(100) DEFAULT NULL, state varchar(100) DEFAULT NULL, country varchar(100) DEFAULT NULL )
NOTE : Above script is written for SQL Server, you can change accordingly for different DB.
Adding Hibernate Jars
Download latest Hibernate jars from here http://hibernate.org/ and add to your classpath.Create Model Classes (Shared primary key technique)
As a next step let’s create the model classes Student.java and StudentAddress.java using Annotations. @PrimaryKeyJoinColumn is the main annotation to be used in shared primary key technique. The model classes are as belowStudent.java
package com.tutorialsdesk.hibernate.bean; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; import javax.persistence.UniqueConstraint; @Entity @Table(name="STUDENT",uniqueConstraints = { @UniqueConstraint(columnNames = "student_id") }) public class Student implements Serializable { private static final long serialVersionUID = 5502738307095121008L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "student_id") private int id; @Column(name="rollno") private String rollno; @Column(name="firstname") private String firstname; @Column(name="lastname") private String lastname; @Column(name="course") private String course; @OneToOne(cascade = CascadeType.ALL) @PrimaryKeyJoinColumn private StudentAddress address; public Student(){ } public Student(String rollno, String firstname, String lastname, String course, StudentAddress address) { super(); this.rollno = rollno; this.firstname = firstname; this.lastname = lastname; this.course = course; this.address = address; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getRollno() { return rollno; } public void setRollno(String rollno) { this.rollno = rollno; } 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 getCourse() { return course; } public void setCourse(String course) { this.course = course; } public StudentAddress getAddress() { return address; } public void setAddress(StudentAddress address) { this.address = address; } }In the above file we see that we have used @PrimaryKeyJoinColumn for the Address entity. Following if a piece of code from the above file:
@OneToOne(cascade = CascadeType.ALL) @PrimaryKeyJoinColumn private StudentAddress address;
StudentAddress.java
package com.tutorialsdesk.hibernate.bean; import java.io.Serializable; 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.Table; import javax.persistence.UniqueConstraint; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; @Entity @Table(name = "STUDENT_ADDRESS", uniqueConstraints = { @UniqueConstraint(columnNames = "student_id") }) public class StudentAddress implements Serializable { /** * */ private static final long serialVersionUID = 7871228112490214979L; @Id @Column(name = "student_id", unique = true, nullable = false) @GeneratedValue(generator = "gen") @GenericGenerator(name = "gen", strategy = "foreign",parameters = @Parameter(name = "property", value = "student")) private int studentId; @Column(name="address") private String address; @Column(name="city") private String city; @Column(name="state") private String state; @Column(name="country") private String country; @OneToOne(mappedBy = "address", cascade = CascadeType.ALL) private Student student; public StudentAddress() { } public int getStudentId() { return studentId; } public StudentAddress(String address, String city, String state, String country) { super(); this.address = address; this.city = city; this.state = state; this.country = country; } public void setStudentId(int studentId) { this.studentId = studentId; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getState() { return state; } public void setState(String state) { this.state = state; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; } }Here we see that Address entity will remain dependent on owner entity for the mapping. Following is a piece of code from the above file:
@OneToOne(mappedBy = "address", cascade = CascadeType.ALL) private Student student;
Adding Hibernate Configuration file
The hibernate.cfg.xml is as follows:<?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> <property name="hibernate.connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property> <property name="hibernate.connection.password">yourpassword</property> <property name="hibernate.connection.url">jdbc:jtds:sqlserver://localhost:1433/yourdbname</property> <property name="hibernate.connection.username">yourusername</property> <property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property> <property name="connection.pool_size">1</property> <property name="hbm2ddl.auto">create</property> <property name="show_sql">true</property> <property name="format_sql">true</property> <mapping class="com.tutorialsdesk.hibernate.bean.Student"/> <mapping class="com.tutorialsdesk.hibernate.bean.StudentAddress"/> </session-factory> </hibernate-configuration>In the above file we have set the database connection to SQL Server database . The show_sql option, if set to true will display all the executed SQL queries on the console. The property hbm2ddl.auto , if set to create, creates the schema, destroying the previous data.
Note : In case you want to use any other database then, you need to change these properties – “dialect”, “connection.driver_class”, “connection.url”, “connection.username”, and “connection.password”.
Also we have added the Annotation based entity classes Student.java and StudentAddress.java to the above file.
Create Utility class
Next, we will write a utility class to take care of Hibernate start up and retrieve the session easily. We will write the file HibernateUtil.java as below:package com.tutorialsdesk.hibernate; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { return new AnnotationConfiguration().configure().buildSessionFactory(); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } public static void shutdown() { getSessionFactory().close(); } }
Main AnnotationTest class
This class tests the one-to-one relationship by creating and listing the student details and corresponding addresses as below:package com.tutorialsdesk.hibernate; import java.util.ArrayList; import org.hibernate.*; import com.tutorialsdesk.hibernate.bean.Student; import com.tutorialsdesk.hibernate.bean.StudentAddress; public class AnnotationTest { public static void main(String[] args) { AnnotationTest test=new AnnotationTest(); StudentAddress sa1 = new StudentAddress("C-42","Noida","UP","IN"); StudentAddress sa2 = new StudentAddress("D-61","Agra","UP","IN"); Student s1=new Student("CS1","Ankit","Yadav","MCA",sa1); Student s2=new Student("CS2","Rahul","Jena","B.Tech",sa1); sa1.setStudent(s1); s1.setAddress(sa1); sa2.setStudent(s2); s2.setAddress(sa2); test.saveStudent(s1); test.saveStudent(s2); test.getStudent(); System.out.println("successfully saved"); } public void saveStudent(Student student) { Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); session.save(student); session.getTransaction().commit(); } public void updateStudent(Student student) { Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); session.merge(student); session.getTransaction().commit(); } public void deleteStudent(Student student) { Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); session.delete(student); session.getTransaction().commit(); } public void getStudent() { Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); @SuppressWarnings("unchecked") ArrayList<Student> list = (ArrayList<Student>) session.createQuery("from Student").list(); if (list != null) { for (int i = 0; i < list.size(); i++) { System.out.println("User ID : " + list.get(i).getId()); System.out.println("User First Name : "+ list.get(i).getFirstname()); System.out.println("User Last Name : "+ list.get(i).getLastname()); System.out.println("User Roll No : " + list.get(i).getRollno()); System.out.println("User Course : " + list.get(i).getCourse()); System.out.println("User Address : " + list.get(i).getAddress().getAddress() + ","+ list.get(i).getAddress().getCity() +"\n"+ list.get(i).getAddress().getState() +"\n"+ list.get(i).getAddress().getCountry()); } } session.getTransaction().commit(); } }Here the saveStudent() method is used to save a new Person object and Address object to the database. In the saveStudent() method a new object of the Student class is created and the name value and address is set. The studentId value is auto generated so the value need not be set here. We then save the Student object to the Address object. The session.save() method is used to persist the value in the database and once the value is saved, the id value (Primary key) is returned. Once the object is saved, the transaction is committed. If any exception occurs then the transaction is rolledback. The transaction ends either through commit or rollback action. Once the transaction ends the session is closed.
The getStudent() method is used to list name of each student in STUDENT table and their corresponding addresses from STUDENT_ADDRESS table. Here we use Hibernate Query Language (HQL). The query “from Student” returns a list of all the data in the STUDENT table and their corresponding addresses from STUDENT_ADDRESS table. Note that in the HQL we only specify the java class names and not the table names. Later, using the for loop we iterate the list the data from Student and corresponding StudentAddress table and hence display them on the console.
Execute the above code
Execute the above code to demonstrate Hibernate One-To-One mapping.Using Foreign Key Technique
In such a association, refer the Address entity in Student class as follows:@OneToOne @JoinColumn(name="addressId") private Address address;If no @JoinColumn is declared on the owner entity, the defaults apply. A join column(s) will be created in the owner entity table and its name will be the concatenation of the name of the relationship in the owner side, _ (underscore), and the name of the primary key column(s) in the owned side.
In a bidirectional relationship, one of the sides has to be the owner entity. The owner is responsible for the association column(s) update. To declare a side as not responsible for the relationship, the attribute mappedBy is used. mappedBy refers to the property name of the association on the owner side. Following is the example code:
@OneToOne(mappedBy="address") private Person person;
Using a Common Join Table
In this technique, main annotation to be used is @JoinTable. This annotation is used to define the new table name (this is mandatory) and foreign keys from both of the tables. Folllowing is the example code:@OneToOne(cascade = CascadeType.ALL) @JoinTable(name="STU_ADDRESS", joinColumns = @JoinColumn(name="student_id"), inverseJoinColumns = @JoinColumn(name="address_Id")) private Address address;@JoinTable annotation is used in Person class. It declares that a new table STU_ADDRESS will be created with two columns student_Id (primary key of STUDENT table) and addressId (primary key of STUDENT_ADDRESS table).
Hope we are able to explain you Hibernate One-To-One Mapping Using Java Annotations, if you have any questions or suggestions please write to us using contact us form.(Second Menu from top left).
Please share us on social media if you like the tutorial.
Blogger Comment
Facebook Comment