Wednesday, October 14, 2015

Hibernate Uni-directional One-to-One Mapping with Annotation

There are two Hibernate mapping directions.
  • Bi-directional mapping
 Here both student and address objects have reference to each other, thus, address object can retrieve student data.

  • Uni-directional mapping
              Here the relationship is kept only on one side. You can directly retrieve data only from one side.
              Lets consider one to one relationship

                   One student dwells in one Address.
                   One address can be occupied by only one student

    if student domain object has a reference to an address object, but address  domain object does not have a reference to the student object, only from a student object you can retrieve address data.


To create a uni-directional mapping using JPA annotation for above relation, we should identify which relation should contain the foreign key. Lets say Student relation contains the foreign key. Therefore, we need a reference to the address and address class will not have any reference

Address class looks like this

package com.sajith.domain;

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

/**
 * Address domain object
 */

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

 @Id
 @Column(name = "ADDRESS_NO")
 private int addressNo;

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

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

 public int getAddressNo() {
  return addressNo;
 }

 public void setAddressNo(int addressNo) {
  this.addressNo = addressNo;
 }

 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;
 }

}
 
 
In this class addressNo field represents primary key table column ADDRESS_NO. This column is the foreign key column in STUDENT table. To represent this relationship in Student class will contain the address as a field and annotations will be used to indicate that it is the mapping field and hold the foreign key.

Student class as follow
package com.sajith.domain;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

/**
 * Student Domain class
 * 
 */

@Entity
@Table(name = "STUDENT")
public class Student {

 private int studentId;

 private String studentName;

 private Address studentAddress;

 @Id
 @Column(name = "ID")
 @GeneratedValue
 public int getStudentId() {
  return studentId;
 }

 public void setStudentId(int studentId) {
  this.studentId = studentId;
 }

 @Column(name = "NAME")
 public String getStudentName() {
  return studentName;
 }

 public void setStudentName(String studentName) {
  this.studentName = studentName;
 }

 @OneToOne(cascade = CascadeType.ALL)
 @JoinColumn(name = "ADDRESS_NO")
 public Address getStudentAddress() {
  return studentAddress;
 }

 public void setStudentAddress(Address studentAddress) {
  this.studentAddress = studentAddress;
 }

}

@OneToOne - States the relationship type
   CascadeType.ALL - States that when changes happen to Student, the corresponding Address should be   changed as well
E.g:  If student is deleted his address should be deleted as well.
@JoinColumn:  States the foreign key column

Get the Hibernate configuration file from my previous Hibernate post and adds the Address class
 <mapping class="com.sajith.domain.Address"/>

Hibernate Util class


package com.sajith.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

 private static final SessionFactory sessionFactory = buildSessionFactory();

 private static ServiceRegistry serviceRegistry;

 private static SessionFactory buildSessionFactory() {

  Configuration configuration = new Configuration();
  configuration.configure();
  serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
    configuration.getProperties()).build();

  return configuration.buildSessionFactory(serviceRegistry);

 }

 public static SessionFactory getSessionFactory() {
  return sessionFactory;
 }

 public static void shutdown() {
  // Close caches and connection pools
  getSessionFactory().close();
 }

} 

Main App class
package com.sajith;

import org.hibernate.Session;

import com.sajith.domain.Address;
import com.sajith.domain.Student;
import com.sajith.util.HibernateUtil;

public class App {

 
 public static void main(String[] args) {
  
 
  Session session = HibernateUtil.getSessionFactory().openSession();

  session.beginTransaction();
   
  Student student1 = new Student();
  
  Address address  = new Address();
  
  address.setAddressNo(2);
  address.setCity("Colombo");
  address.setStreet("Horton Place");
  
  
  student1.setStudentId(3);
                student1.setStudentName("Sanya Fernando");
                student1.setStudentAddress(address);
 
 

  session.save(student1);
  session.getTransaction().commit();
  
  System.exit(0);
 }
 
}

As you can see we create a Student instance and assign an address.
Create the tables like following.

Address table



Student table



If you execute the App file, output will be








Monday, October 12, 2015

Hibernate mapping with Annotation


This is a simple example of mapping a java domain class with a relation using JPA annotation and Hibernate.

Hibernate can be mapped in 2 ways.
  • With an XML mapping file(.hbm file)
  • With Annotation
Description
   We use JPA as Annotation specification and Hibernate as the provider.

Steps

  • Create a java project using Maven in Eclipse and update the pom file

Refer: Hibernate environment setup with maven using Eclipse


  • Create the domain class and annotate using JPA annotation
@Entity - Denotes that instances of this class are persistent with a DB
@Table - Denotes that name of the corresponding table in DB is STUDENT if not used this annotation, table name would be the same as class name(Hence, here it would be Student)
@Id - This field will be the Primary Key column
@Column - Denotes that this will be a column in the table

Mapping can be done for member variables or/and their corresponding getter methods.

package com.sajith.domain;

import javax.annotation.Generated;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Student Domain class
 *
 */

@Entity
@Table(name="STUDENT")
public class Student {

 
 private int studentId;
 
 private String studentName;
 
 private String studnetCity;

 @Id
 @Column(name="ID")
 public int getStudentId() {
  return studentId;
 }

 
 public void setStudentId(int studentId) {
  this.studentId = studentId;
 }

 @Column(name="CITY")
 public String getStudnetCity() {
  return studnetCity;
 }

 public void setStudnetCity(String studnetCity) {
  this.studnetCity = studnetCity;
 }

 @Column(name="NAME")
 public String getStudentName() {
  return studentName;
 }

 public void setStudentName(String studentName) {
  this.studentName = studentName;
 }

}


  • Create the Hibernate configuration file
  When you use annotation instead of XML mapping only change will be instead of <mapping resource>
<mapping class> attribute.

<?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">oracle.jdbc.driver.OracleDriver</property>
        <property name="hibernate.connection.password">sajith</property>
        <property name="hibernate.connection.url">jdbc:oracle:thin:@127.0.0.1:1521:xe</property>
        <property name="hibernate.connection.username">sajith</property>
        <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
        <property name="show_sql">true</property>
        <property name="hbmdl.auto">update</property>
        <mapping class="com.sajith.domain.Student"/>
    </session-factory>
</hibernate-configuration>


  • Create the Util class

package com.sajith.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

 private static final SessionFactory sessionFactory = buildSessionFactory();
 
 private static ServiceRegistry serviceRegistry;

 private static SessionFactory buildSessionFactory() {
  
   Configuration configuration = new Configuration();
   configuration.configure();
   serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
          configuration.getProperties()).build();
  
  return configuration.buildSessionFactory(serviceRegistry);
       
  
 }

 public static SessionFactory getSessionFactory() {
  return sessionFactory;
 }

 public static void shutdown() {
  // Close caches and connection pools
  getSessionFactory().close();
 }
 
}

  • Create the main App class
 
package com.sajith;

import org.hibernate.Session; 
import com.sajith.domain.Student;
import com.sajith.util.HibernateUtil;

public class App {

 
 public static void main(String[] args) {
  
 
  Session session = HibernateUtil.getSessionFactory().openSession();

  session.beginTransaction();
   
  Student student1 = new Student();
  
  student1.setStudentId(1);
                student1.setStudentName("Sanya Fernando");
                student1.setStudnetCity("Kandy");
 
  session.save(student1);
  session.getTransaction().commit();
  
  
 }
 
}
 
  • Run the App file





Hibernate environment setup with maven using Eclipse

Hibernate is an ORM tool framework which can be used to abstract the JDBC and access various DBMSs independently from DBMS specific SQL. Hibernate provides a way to developer to write SQL using domain model instead of data model representing in DB.

Hibernate mapping types

1. XML mapping files
2. Annotation

The application of Hibernate


1. Pure Hibernate - Only Hibernate framework is used as the mapping framework.
2. With JPA  - Java standardized API for mapping. Here JPA works as the specification and Hibernate is the provider. This is the recommended development method; while JPA annotation is used as the ORM interface, Hibernate provides the implementation. The advantage is you can easily replace the ORM implementation for another ORM framework.

1. Simple Domain object to Oracle table mapping in Hibernate


Hibernate setup with maven in Eclipse

Required Tools & technologies:
  1. Maven 3.1.1
  2. JBOSS hibernate tools
  3. JDK 1.7
  4. Hibernate 4.3.6.final
  5. Oracle 11g
  6. maven-compiler-plugin 3.3
  7. Ojdbc 11.1.0.7
Steps

  • Create a simple maven project skipping archetype
  • Update .pom file with adding following entries
    <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.sajith.hibernate</groupId>
     <artifactId>HibernateStart</artifactId>
     <version>0.0.1-SNAPSHOT</version>
    
     <repositories>
      <repository>
       <id>JBoss repository</id>
       <url>http://repository.jboss.org/nexus/content/groups/public/</url>
      </repository>
     </repositories>
            <dependencies>
      <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-core</artifactId>
       <version>4.3.6.Final</version>
      </dependency>
      <dependency>
       <groupId>com.oracle</groupId>
       <artifactId>ojdbc6</artifactId>
       <version>11.1.0.7</version>
      </dependency>
      <dependency>
       <groupId>org.javassist</groupId>
       <artifactId>javassist</artifactId>
       <version>3.18.1-GA</version>
      </dependency>
     </dependencies>
     <build>
      <plugins>
       <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.3</version>
        <configuration>
         <source>1.7</source>
         <target>1.7</target>
        </configuration>
       </plugin>
      </plugins>
     </build>
    </project>
         Here we use a plug-in to change the default maven compiler and run time version from 1.5 to 1.7
         We add JBOSS repository to get the required Hibernate jars downloaded. And, finally add Oracle
         driver. Oracle drive, you have to download manually and install in your local maven repository.

   
  • Create the domain class

package com.sajith.domain;

/**
 * Student Domain class
 *
 */
public class Student {

 private int studentId;
 private String studentName;
 private String studnetCity;

 public int getStudentId() {
  return studentId;
 }

 public void setStudentId(int studentId) {
  this.studentId = studentId;
 }

 public String getStudnetCity() {
  return studnetCity;
 }

 public void setStudnetCity(String studnetCity) {
  this.studnetCity = studnetCity;
 }

 public String getStudentName() {
  return studentName;
 }

 public void setStudentName(String studentName) {
  this.studentName = studentName;
 }

}
  
  •  Create Hibernate mapping file - Student.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Oct 12, 2015 2:15:25 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.sajith.domain.Student" table="STUDENT">
        <id name="studentId" type="int">
            <column name="ID" />
            <generator class="assigned" />
        </id>
        <property name="studentName" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="studnetCity" type="java.lang.String">
            <column name="CITY" />
        </property>
    </class>
</hibernate-mapping>

   
  • Create Hibernate configuration file - hibernate.cfg.xml
<?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">oracle.jdbc.driver.OracleDriver</property>
        <property name="hibernate.connection.password">sajith</property>
        <property name="hibernate.connection.url">jdbc:oracle:thin:@127.0.0.1:1521:xe</property>
        <property name="hibernate.connection.username">sajith</property>
        <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
        <property name="show_sql">true</property>
        <property name="hbmdl.auto">update</property>
        <mapping resource="com/sajith/domain/Student.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

 
Here, xe is the SID
  •  Create Hibernate Util class
 
 
package com.sajith.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

 private static final SessionFactory sessionFactory = buildSessionFactory();
 
 private static ServiceRegistry serviceRegistry;

 private static SessionFactory buildSessionFactory() {
  
   Configuration configuration = new Configuration();
   configuration.configure();
   serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
          configuration.getProperties()).build();
  
  return configuration.buildSessionFactory(serviceRegistry);
       
  
 }

 public static SessionFactory getSessionFactory() {
  return sessionFactory;
 }

 public static void shutdown() {
  // Close caches and connection pools
  getSessionFactory().close();
 }
 
}

  •       Create the main app class
 
package com.sajith;

import org.hibernate.Session; 
import com.sajith.domain.Student;
import com.sajith.util.HibernateUtil;

public class App {

 
 public static void main(String[] args) {
  
 
  Session session = HibernateUtil.getSessionFactory().openSession();

  session.beginTransaction();
   
  Student student1 = new Student();
  
  student1.setStudentId(1);
                student1.setStudentName("Sanya Fernando");
                student1.setStudnetCity("Kandy");
 
  session.save(student1);
  session.getTransaction().commit();
  
  
 }
 
}
   
Note that both configuration files should be in class path to run the application.

  • Run the app file and see the result in the DB. you can also see the log result in Eclipse console window
             Hibernate: insert into STUDENT (NAME, CITY, ID) values (?, ?, ?)