Hibernate Inheritance: Table Per Concrete Class

Hi Guys now its time to look at Table per concrete class hierarchy in hibernate. lets have a scenario where we have three classes Bike,BikeDetails and BikeEngine is the super class to the other two classes.In One Table per Concrete class scheme, each concrete class is mapped as normal persistent class. Thus we have 3 tables; Bike, BikeDetails and BikeEngine to persist the class data. In this scheme, the mapping of the subclass repeats the properties of the parent class.

Advantages
This is the easiest method of Inheritance mapping to implement.

Disadvantages
Data thats belongs to a parent class is scattered across a number of subclass tables, which represents concrete classes.
This hierarchy is not recommended for most cases.
Changes to a parent class is reflected to large number of tables
A query couched in terms of parent class is likely to cause a large number of select operations

following is the sql script to create the database.

DROP TABLE IF EXISTS `test`.`bike`;
CREATE TABLE  `test`.`bike` (
  `bike_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `bike_name` varchar(45) NOT NULL,
  `company` varchar(45) NOT NULL,
  PRIMARY KEY (`bike_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `test`.`bike_details`;
CREATE TABLE  `test`.`bike_details` (
  `bike_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `bike_cost` int(10) unsigned NOT NULL,
  `manufacture_date` date NOT NULL,
  `bike_name` varchar(45) NOT NULL,
  `company` varchar(45) NOT NULL,
  PRIMARY KEY (`bike_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `test`.`bike_engine`;
CREATE TABLE  `test`.`bike_engine` (
  `bike_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `engine_type` varchar(45) NOT NULL,
  `engine_cc` varchar(45) NOT NULL,
  `engine_bhp` varchar(45) NOT NULL,
  `bike_name` varchar(45) NOT NULL,
  `company` varchar(45) NOT NULL,
  PRIMARY KEY (`bike_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Following is the example where we map Bike, BikeDetails and BikeEngine entity classes using XML mapping.
Bike.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;

/**
 * @author Sony
 * 
 */
public class Bike implements Serializable {

	private int bikeId;
	private String bikeName;
	private String company;
	
	public Bike() {
		// TODO Auto-generated constructor stub
	}
	
	public Bike(String bikeName,String company) {
		this.bikeName = bikeName;
		this.company = company;
	}

	/**
	 * @return the bikeId
	 */
	public int getBikeId() {
		return bikeId;
	}

	/**
	 * @param bikeId
	 *            the bikeId to set
	 */
	public void setBikeId(int bikeId) {
		this.bikeId = bikeId;
	}

	/**
	 * @return the bikeName
	 */
	public String getBikeName() {
		return bikeName;
	}

	/**
	 * @param bikeName
	 *            the bikeName to set
	 */
	public void setBikeName(String bikeName) {
		this.bikeName = bikeName;
	}

	/**
	 * @return the company
	 */
	public String getCompany() {
		return company;
	}

	/**
	 * @param company
	 *            the company to set
	 */
	public void setCompany(String company) {
		this.company = company;
	}

}

BikeDetails.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;
import java.util.Date;

/**
 * @author Sony
 * 
 */
public class BikeDetails extends Bike implements Serializable {

	private int bikeCost;
	private Date manufactureDate;

	public BikeDetails() {
		// TODO Auto-generated constructor stub
	}

	public BikeDetails(String bikeName, String company, int bikeCost,
			Date manufactureDate) {
		super(bikeName, company);
		this.bikeCost = bikeCost;
		this.manufactureDate = manufactureDate;
	}

	/**
	 * @return the bikeCost
	 */
	public int getBikeCost() {
		return bikeCost;
	}

	/**
	 * @param bikeCost
	 *            the bikeCost to set
	 */
	public void setBikeCost(int bikeCost) {
		this.bikeCost = bikeCost;
	}

	/**
	 * @return the manufactureDate
	 */
	public Date getManufactureDate() {
		return manufactureDate;
	}

	/**
	 * @param manufactureDate
	 *            the manufactureDate to set
	 */
	public void setManufactureDate(Date manufactureDate) {
		this.manufactureDate = manufactureDate;
	}

}

BikeEngine.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;

/**
 * @author Sony
 * 
 */
public class BikeEngine extends Bike implements Serializable {

	private String engineType;
	private String engineBHP;
	private String engineCC;

	public BikeEngine() {
		// TODO Auto-generated constructor stub
	}

	public BikeEngine(String bikeName, String company, String engineType,
			String engineBHP, String engineCC) {
		super(bikeName, company);
		this.engineType = engineType;
		this.engineBHP = engineBHP;
		this.engineCC = engineCC;
	}

	/**
	 * @return the engineType
	 */
	public String getEngineType() {
		return engineType;
	}

	/**
	 * @param engineType
	 *            the engineType to set
	 */
	public void setEngineType(String engineType) {
		this.engineType = engineType;
	}

	/**
	 * @return the engineBHP
	 */
	public String getEngineBHP() {
		return engineBHP;
	}

	/**
	 * @param engineBHP
	 *            the engineBHP to set
	 */
	public void setEngineBHP(String engineBHP) {
		this.engineBHP = engineBHP;
	}

	/**
	 * @return the engineCC
	 */
	public String getEngineCC() {
		return engineCC;
	}

	/**
	 * @param engineCC
	 *            the engineCC to set
	 */
	public void setEngineCC(String engineCC) {
		this.engineCC = engineCC;
	}

}

lets construct a hbm file with multiple classes mappings as follows.

<?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 17 Jun, 2013 9:42:56 AM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="com.spark.hibernate.model">

	<class name="Bike" table="BIKE">
		<id name="bikeId" type="int">
			<column name="BIKE_ID" />
			<generator class="native" />
		</id>
		<property name="bikeName" type="java.lang.String">
			<column name="BIKE_NAME" />
		</property>
		<property name="company" type="java.lang.String">
			<column name="COMPANY" />
		</property>
	</class>

	<class name="BikeDetails" table="BIKE_DETAILS">
		<id name="bikeId" type="int">
			<column name="BIKE_ID" />
			<generator class="native" />
		</id>
		<property name="bikeCost" column="bike_cost"></property>
		<property name="manufactureDate" column="manufacture_date"
			type="date"></property>
		<property name="bikeName" column="bike_name"></property>
		<property name="company" column="company"></property>
	</class>

	<class name="BikeEngine" table="BIKE_ENGINE">
		<id name="bikeId" type="int">
			<column name="BIKE_ID" />
			<generator class="native" />
		</id>
		<property name="engineType" column="engine_type"></property>
		<property name="engineCC" column="engine_cc"></property>
		<property name="engineBHP" column="engine_bhp"></property>
		<property name="bikeName" column="bike_name"></property>
		<property name="company" column="company"></property>
	</class>
	
</hibernate-mapping>

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">com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.password">root</property>
  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
  <property name="hibernate.connection.username">root</property>
  <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  <property name="hibernate.query.startup_check">true</property>
  <property name="hibernate.show_sql">true</property>
  <property name="hibernate.use_sql_comments">true</property>
  <property name="hibernate.format_sql">true</property>
  
  <mapping resource="com/spark/hibernate/model/Bike.hbm.xml"/>
  
 </session-factory>
</hibernate-configuration>

Main.java

/**
 * 
 */
package com.spark.hibernate.main;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.spark.hibernate.model.Account;
import com.spark.hibernate.model.AccountHolder;
import com.spark.hibernate.model.AccountTransactions;
import com.spark.hibernate.model.Bike;
import com.spark.hibernate.model.BikeDetails;
import com.spark.hibernate.model.BikeEngine;
import com.spark.hibernate.util.HibernateUtil;

/**
 * @author Sony
 *
 */
public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		Logger logger = LoggerFactory.getLogger(Main.class);
		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();
		logger.info("-----------------Session created------------------");
		session.beginTransaction();
		logger.info("-----------------Transaction Started------------------");
		
		Bike bike = new Bike("R15", "Yamaha");
		session.persist(bike);
		logger.info("-------------Bike Object Persisted----------");
		
		BikeEngine bikeEngine = new BikeEngine("R15", "Yamaha","OilCooled","10.5","180");
		session.persist(bikeEngine);
		logger.info("-------------BikeEngine Object Persisted----------");
		
		BikeDetails bikeDetails = new BikeDetails("R15", "Yamaha",48000,new Date());
		session.persist(bikeDetails);
		logger.info("-------------BikeDetails Object Persisted----------");
		
		session.getTransaction().commit();
		logger.info("-----------------Transaction Commited------------------");
		session.close();
		logger.info("-----------------Session Closed------------------");
		sessionFactory.close();
		logger.info("-----------------SessionFactory Closed------------------");
		
	}

}

note:get the HibernateUtil from the previous posts
output:
Table_Per_Concrete_Class
That is it,
Happy Coding πŸ™‚

Advertisements

Hibernate Inheritance: Table Per SubClass hierarchy(annotations)

Hi guys, here i am going to explain how to implement table per subclass hierarchy using annotations. with a little change to my previous post we can achieve this strategy.

just change all the Entity’s to annotated style as shown below.
AccountHolder.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

/**
 * @author Sony
 * 
 */
@Entity
@Table(name="account_holder")
@Inheritance(strategy=InheritanceType.JOINED)
public class AccountHolder implements Serializable {

	private int accountId;
	private String firstName;
	private String lastName;

	public AccountHolder() {

	}
	
	public AccountHolder(String firstName,String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}
	
	/**
	 * @return the accountId
	 */
	@Id
	@GeneratedValue
	@Column(name="account_id")
	public int getAccountId() {
		return accountId;
	}

	/**
	 * @param accountId
	 *            the accountId to set
	 */
	public void setAccountId(int accountId) {
		this.accountId = accountId;
	}

	/**
	 * @return the firstName
	 */
	@Column(name="firstname")
	public String getFirstName() {
		return firstName;
	}

	/**
	 * @param firstName
	 *            the firstName to set
	 */
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	/**
	 * @return the lastName
	 */
	@Column(name="lastname")
	public String getLastName() {
		return lastName;
	}

	/**
	 * @param lastName
	 *            the lastName to set
	 */
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

}

Account.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;

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

/**
 * @author Sony
 * 
 */
@Entity
@Table(name="account")
@PrimaryKeyJoinColumn(name="account_id")
public class Account extends AccountHolder implements Serializable {

	private int rateOfInterest;
	private String accountType;

	public Account() {
		// TODO Auto-generated constructor stub
	}

	public Account(String firstName,String lastName,int rateOfInterest,String accountType) {
		super(firstName,lastName);
		this.rateOfInterest = rateOfInterest;
		this.accountType = accountType;
	}

	/**
	 * @return the rateOfInterest
	 */
	@Column(name="rate_of_interest")
	public int getRateOfInterest() {
		return rateOfInterest;
	}

	/**
	 * @param rateOfInterest
	 *            the rateOfInterest to set
	 */
	public void setRateOfInterest(int rateOfInterest) {
		this.rateOfInterest = rateOfInterest;
	}

	/**
	 * @return the accountType
	 */
	@Column(name="account_type")
	public String getAccountType() {
		return accountType;
	}

	/**
	 * @param accountType
	 *            the accountType to set
	 */
	public void setAccountType(String accountType) {
		this.accountType = accountType;
	}

}

AccountTransactions.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;
import java.util.Date;

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

/**
 * @author Sony
 * 
 */
@Entity
@Table(name="account_transactions")
@PrimaryKeyJoinColumn(name="account_id")
public class AccountTransactions extends AccountHolder implements Serializable {

	private int transactionAmount;
	private String transactionType;
	private Date transactionDate;

	public AccountTransactions() {
		// TODO Auto-generated constructor stub
	}

	public AccountTransactions(String firstName, String lastName,
			int transactionAmount, String transactionType, Date transactionDate) {

		super(firstName, lastName);
		this.transactionAmount = transactionAmount;
		this.transactionDate = transactionDate;
		this.transactionType = transactionType;
	}

	/**
	 * @return the transactionAmount
	 */
	@Column(name="transaction_amount")
	public int getTransactionAmount() {
		return transactionAmount;
	}

	/**
	 * @param transactionAmount
	 *            the transactionAmount to set
	 */
	public void setTransactionAmount(int transactionAmount) {
		this.transactionAmount = transactionAmount;
	}

	/**
	 * @return the transactionType
	 */
	@Column(name="transaction_type")
	public String getTransactionType() {
		return transactionType;
	}

	/**
	 * @param transactionType
	 *            the transactionType to set
	 */
	public void setTransactionType(String transactionType) {
		this.transactionType = transactionType;
	}

	/**
	 * @return the transactionDate
	 */
	@Column(name="transaction_date")
	public Date getTransactionDate() {
		return transactionDate;
	}

	/**
	 * @param transactionDate
	 *            the transactionDate to set
	 */
	public void setTransactionDate(Date transactionDate) {
		this.transactionDate = transactionDate;
	}

}

Now little explanation regarding the annotations follows,
The AccountHolder class is the root of hierarchy. Hence we have used some annotations to make it as the root.

@Inheritance – Defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the entity class that is the root of the entity class hierarchy.

@InheritanceType – Defines inheritance strategy options. JOINED is a strategy in which fields that are specific to a subclass are mapped to a separate table than the fields that are common to the parent class, and a join is performed to instantiate the subclass. Thus fields of Account (accountType, rateOfIntrest) and AccountTransactions (transactionAmount etc) are mapped to their respective tables.Both Account and AccountTransactions classes are child of AccountHolder class. Thus while specifying the mappings, we used @PrimaryKeyJoinColumn to map it to parent table.

@PrimaryKeyJoinColumn – This annotation specifies a primary key column that is used as a foreign key to join to another table.

It is used to join the primary table of an entity subclass in the JOINED mapping strategy to the primary table of its superclass, it is used within a SecondaryTable annotation to join a secondary table to a primary table; and it may be used in a OneToOne mapping in which the primary key of the referencing entity is used as a foreign key to the referenced entity.

Note: If no PrimaryKeyJoinColumn annotation is specified for a subclass in the JOINED mapping strategy, the foreign key columns are assumed to have the same names as the primary key columns of the primary table of the superclass

Now lets change the configuration file to identify these annotated entities.

<?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">com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.password">root</property>
  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
  <property name="hibernate.connection.username">root</property>
  <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  <property name="hibernate.query.startup_check">true</property>
  <property name="hibernate.show_sql">true</property>
  <property name="hibernate.use_sql_comments">true</property>
  <property name="hibernate.format_sql">true</property>
  
  <mapping class="com.spark.hibernate.model.AccountHolder"/>
  <mapping class="com.spark.hibernate.model.Account"/>
  <mapping class="com.spark.hibernate.model.AccountTransactions"/>
  
 </session-factory>
</hibernate-configuration>

That is it, with the help of HibernateUtil and Main from the previous post you can run this code.
output:
Table_Per_Sub_Class
Happy Coding πŸ™‚

Hibernate Inheritance: Table Per Class hierarchy(Annotation)

Hi Guys, to my previous post i want to add annotation capability. There is not much change in the project structure but only minor changes are required. To the Person.java and Employee.java we add Annotation Capabilities, prior to adding annotations please add javaee-api-5.jar or javaee.jar in order to get the persistence annotation to your build path.

Person.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

/**
 * @author Sony
 * 
 */
@Entity
@Table(name="person")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(discriminatorType=DiscriminatorType.STRING,name="discriminator")
@DiscriminatorValue(value="P")
public class Person implements Serializable {

	private int personId;
	private String firstName;
	private String lastName;
	
	public Person() {
		// TODO Auto-generated constructor stub
	}
	
	public Person(String firstName,String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}

	/**
	 * @return the personId
	 */
	@Id
	@GeneratedValue
	@Column(name="person_id")
	public int getPersonId() {
		return personId;
	}

	/**
	 * @param personId
	 *            the personId to set
	 */
	public void setPersonId(int personId) {
		this.personId = personId;
	}

	/**
	 * @return the firstName
	 */
	@Column(name="firstname")
	public String getFirstName() {
		return firstName;
	}

	/**
	 * @param firstName
	 *            the firstName to set
	 */
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	/**
	 * @return the lastName
	 */
	@Column(name="lastname")
	public String getLastName() {
		return lastName;
	}

	/**
	 * @param lastName
	 *            the lastName to set
	 */
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

}

Employee.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;
import java.util.Date;

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

/**
 * @author Sony
 * 
 */
@Entity
@Table(name="person")
@DiscriminatorValue(value="E")
public class Employee extends Person implements Serializable {

	private Date joiningDate;
	private String departmentName;
	
	public Employee() {
		// TODO Auto-generated constructor stub
	}
	
	public Employee(String firstName,String lastName,Date joiningDate,String departmentName) {
		super(firstName,lastName);
		this.joiningDate = joiningDate;
		this.departmentName = departmentName;
	}

	/**
	 * @return the joiningDate
	 */
	@Column(name="joining_date")
	public Date getJoiningDate() {
		return joiningDate;
	}

	/**
	 * @param joiningDate
	 *            the joiningDate to set
	 */
	public void setJoiningDate(Date joiningDate) {
		this.joiningDate = joiningDate;
	}

	/**
	 * @return the departmentName
	 */
	@Column(name="department_name")
	public String getDepartmentName() {
		return departmentName;
	}

	/**
	 * @param departmentName
	 *            the departmentName to set
	 */
	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}

}

Lets have little discussion about annotation in the code above:
The Person class is at the root of hierarchy. Hence we have used some annotations to make it as the root.

@Inheritance – Defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the root of the entity class hierarchy.

@DiscriminatorColumn – Is used to define the discriminator column for the SINGLE_TABLE and JOINED inheritance mapping strategies. The strategy and the discriminator column are only specified in the root of an entity class hierarchy or sub hierarchy in which a different inheritance strategy is applied

If the @DiscriminatorColumn annotation is missing, and a discriminator column is required, the name of the discriminator column defaults to “DTYPE” and the discriminator type to DiscriminatorType.STRING.

@DiscriminatorValue – Is used to specify the value of the discriminator column for entities of the given type. The DiscriminatorValue annotation can only be specified on a concrete entity class. If the DiscriminatorValue annotation is not specified and a discriminator column is used, a provider-specific function will be used to generate a value representing the entity type. If the DiscriminatorType is STRING, the discriminator value default is the entity name.

The inheritance strategy and the discriminator column are only specified in the root of an entity class hierarchy or subhierarchy in which a different inheritance strategy is applied. The discriminator value, if not defaulted, should be specified for each entity class in the hierarchy.

after all these major changes small tweeks are required in hibernate.cfg.xml 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">com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.password">root</property>
  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
  <property name="hibernate.connection.username">root</property>
  <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  <property name="hibernate.query.startup_check">true</property>
  <property name="hibernate.show_sql">true</property>
  <property name="hibernate.use_sql_comments">true</property>
  <property name="hibernate.format_sql">true</property>
  <mapping class="com.spark.hibernate.model.Person"/>
  <mapping class="com.spark.hibernate.model.Employee"/>
  <!-- <mapping resource="com/spark/hibernate/model/Person.hbm.xml"/> -->
 </session-factory>
</hibernate-configuration>

now the helper class changes as follows:

/**
 * 
 */
package com.spark.hibernate.util;

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

/**
 * @author Sony
 *
 */
public class HibernateUtil {

	private static SessionFactory sessionFactory;
	
	public static SessionFactory getSessionFactory(){
		
		//sessionFactory = new Configuration().configure().buildSessionFactory();
		sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
		return sessionFactory;
	}
}

Now the changes are done your main class remains as it is, and the out put should be the same as the previous one.
Happy Coding πŸ™‚

Hibernate Inheritance: Table Per Class hierarchy

Hi Guys, Here i am going to discuss some of the best features of Hibernate framework. For the next few classes i am going to discuss about inheritance in Java and how to implement it in Hibernate.

Object oriented systems are majorly implemented with β€œis a” and β€œhas a” relationship. Relational databases supports only β€œhas a” relationship between two entities. Hibernate can help you map such Objects with relational tables, only thing is we need to choose certain mapping strategy based on our needs.

Table Per Class Hierarchy:
Let us consider we have a Person class and Employee class which extend from Person class

Class Person {
property firstName
property lastName
}


Class Employee extends Person{
property joiningDate
property departmentName
}

In Table per Class Hierarchy , we store all the class hierarchy in a single table. A discriminator is a key to uniquely identify the base type of the class hierarchy.i.e we store the Employee and Person related information in Person table in database.

Following are the advantages and disadvantages of Table per Class Hierarchy.
Advantage
This hierarchy offers the best performance even for in the deep hierarchy since single select may suffice.
Disadvantage
The columns for properties declared by subclasses must be declared to accept null Values, these columns cannot be declared with NOT NULL constraint.

Following is the Sql script:

DROP TABLE IF EXISTS `test`.`person`;
CREATE TABLE  `test`.`person` (
  `person_id` bigint(10) NOT NULL AUTO_INCREMENT,
  `firstname` varchar(50) DEFAULT NULL,
  `lastname` varchar(50) DEFAULT NULL,
  `joining_date` date DEFAULT NULL,
  `department_name` varchar(50) DEFAULT NULL,
  `discriminator` varchar(20) NOT NULL,
  PRIMARY KEY (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

In the following example i’ll demonstrate the mapping using hbm.xml file and next by annotation.
Person.Java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;

/**
 * @author Sony
 * 
 */
public class Person implements Serializable {

	private int personId;
	private String firstName;
	private String lastName;
	
	public Person() {
		// TODO Auto-generated constructor stub
	}
	
	public Person(String firstName,String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}

	/**
	 * @return the personId
	 */
	public int getPersonId() {
		return personId;
	}

	/**
	 * @param personId
	 *            the personId to set
	 */
	public void setPersonId(int personId) {
		this.personId = personId;
	}

	/**
	 * @return the firstName
	 */
	public String getFirstName() {
		return firstName;
	}

	/**
	 * @param firstName
	 *            the firstName to set
	 */
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	/**
	 * @return the lastName
	 */
	public String getLastName() {
		return lastName;
	}

	/**
	 * @param lastName
	 *            the lastName to set
	 */
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

}

Employee.java

/**
 * 
 */
package com.spark.hibernate.model;

import java.io.Serializable;
import java.util.Date;

/**
 * @author Sony
 * 
 */
public class Employee extends Person implements Serializable {

	private Date joiningDate;
	private String departmentName;
	
	public Employee() {
		// TODO Auto-generated constructor stub
	}
	
	public Employee(String firstName,String lastName,Date joiningDate,String departmentName) {
		super(firstName,lastName);
		this.joiningDate = joiningDate;
		this.departmentName = departmentName;
	}

	/**
	 * @return the joiningDate
	 */
	public Date getJoiningDate() {
		return joiningDate;
	}

	/**
	 * @param joiningDate
	 *            the joiningDate to set
	 */
	public void setJoiningDate(Date joiningDate) {
		this.joiningDate = joiningDate;
	}

	/**
	 * @return the departmentName
	 */
	public String getDepartmentName() {
		return departmentName;
	}

	/**
	 * @param departmentName
	 *            the departmentName to set
	 */
	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}

}

Now lets look at hibernate.cfg.xml which allows the configuration for hibernate framework.

<?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">com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.password">Password</property>
  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
  <property name="hibernate.connection.username">root</property>
  <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  <property name="hibernate.query.startup_check">true</property>
  <property name="hibernate.show_sql">true</property>
  <property name="hibernate.use_sql_comments">true</property>
  <property name="hibernate.format_sql">true</property>
  <mapping resource="com/spark/hibernate/model/Person.hbm.xml"/>
 </session-factory>
</hibernate-configuration>

Now lets have a look at hbm file i name it as Person.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 15 Jun, 2013 7:42:12 PM by Hibernate Tools 3.4.0.CR1 -->

<hibernate-mapping package="com.spark.hibernate.model">
    <class name="Person" table="PERSON" discriminator-value="P">
        <id name="personId" type="int">
            <column name="PERSON_ID" />
            <generator class="native" />
        </id>
        
        <discriminator column="DISCRIMINATOR" type="string" />
        <property name="firstName" type="java.lang.String">
            <column name="FIRSTNAME" />
        </property>
        <property name="lastName" type="java.lang.String">
            <column name="LASTNAME" />
        </property>
        
        <subclass name="Employee" extends="Person" discriminator-value="E">
        	<property name="joiningDate" type="date" column="joining_date"></property>
        	<property name="departmentName" type="string" column="department_name"></property>
        </subclass>
    </class>
</hibernate-mapping>

Lets have a small discussion on the above file, Note that we have only one hibernate mapping (hbm) file Person.hbm.xml. Both Person and Employee model(POJO) classes are defined within one hbm file.

tag is used to define the discriminator column.
NOTE: your discriminator tag should appear right after the id tag if not you will run into errors

tag is used to map the subclass Employee. Note that we have not used the usual tag to map Employee as it falls below in the hierarchy tree.

The discriminator-value for Person is defined as β€œP” and that for Employee is defined β€œE”, Thus, when Hibernate will persist the data for person or employee it will accordingly populate this value.

Lets have a look at our main class to run:
Main.java

/**
 * 
 */
package com.spark.hibernate.main;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.spark.hibernate.model.Employee;
import com.spark.hibernate.model.Person;
import com.spark.hibernate.util.HibernateUtil;

/**
 * @author Sony
 *
 */
public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();
		
		session.beginTransaction();
		
		Person person = new Person("James","Gosling");
		session.save(person);
		
		Employee employee = new Employee("Bill","Gates",new Date(), "Java Development");
		session.save(employee);
		
		session.getTransaction().commit();
		session.close();
		sessionFactory.close();
		
	}

}

We used a helper class to get the SessionFactory Object of Hibernate, so here it is:

/**
 * 
 */
package com.spark.hibernate.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * @author Sony
 *
 */
public class HibernateUtil {

	private static SessionFactory sessionFactory;
	
	public static SessionFactory getSessionFactory(){
		
		sessionFactory = new Configuration().configure().buildSessionFactory();
		return sessionFactory;
	}
}

Finally the output should look like the following

Table_Per_Class_Query_OP

Table_Per_Class

Happy Coding πŸ™‚