Inheritance in Hibernate:
Java is object oriented language and inheritance is one of main functionalities of java. Relational model can implement "is a" and "has a" relationship. Relational model supports only “has a” relationship between two entities. Hibernate can help you map such Objects with relational tables. But you need to choose certain mapping strategy based on your needs. There are three inheritance mapping strategies defined in the hibernate.
One table per one concrete class (TABLE_PER_CLASS)
One table per all hierarchical classes (SINGLE_TABLE)
One table per one concrete sub class (JOINED)
One table per one concrete class: This mapping is not known as good mapping for projects. In this approach every entity class has its own table i.e. table per class. All the properties of a class including inherited properties are mapped to columns of a table.
There are two ways to map the table with table per concrete class strategy.
By using <union-subclass> element.
By self creating the table for each class.
Lets say we have following class hierarchy.
We have Person class as base class and Employee is subclass of Person and PermanentEmployee is Subclass of Employee.
In table per concrete class, One table will be created for each concrete class. So there table will be three tables created( Person, Employee and PermanenetEmployee) and subclass repeats property of parent class.
Person.java
==============
package com.ranga.mapping;
import java.io.Serializable;
public class Person implements Serializable {
private long id;
private String firstName;
private String lastName;
private int age;
// Constructors and Getter/Setter methods,
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Employee.java
====================
package com.ranga.mapping;
public class Employee extends Person {
private String designation;
private Double salary;
// Constructors and Getter/Setter methods,
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
}
PermanentEmployee.java
=========================
package com.ranga.mapping;
public class PermanentEmployee extends Employee {
private double allowance;
private int noOfLeaves;
// Constructors and Getter/Setter methods,
public double getAllowance() {
return allowance;
}
public void setAllowance(double allowance) {
this.allowance = allowance;
}
public int getNoOfLeaves() {
return noOfLeaves;
}
public void setNoOfLeaves(int noOfLeaves) {
this.noOfLeaves = noOfLeaves;
}
}
1. By self creating the table for each class:
Person.hbm.xml
========================
<?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 package="com.ranga.mapping">
<!-- Table-per-class hierarchy -->
<class name="Person" table="Persons">
<id name="id" />
<property name="firstName" />
<property name="lastName" />
<property name="age" />
</class>
<class name="Employee" table="Employees">
<id name="id" />
<property name="designation" />
<property name="salary" />
</class>
<class name="PermanentEmployee" table="PermanentEmployees">
<id name="id" />
<property name="allowance" />
<property name="noOfLeaves" />
</class>
</hibernate-mapping>
2. By using <union-subclass> element:
<?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 package="com.ranga.mapping">
<!-- Table-per-class hierarchy -->
<class name="Person" table="Persons">
<id name="id" />
<property name="firstName" />
<property name="lastName" />
<property name="age" />
<union-subclass name="Employee" table="Employees">
<property name="designation" />
<property name="salary" />
</union-subclass>
<union-subclass name="PermanentEmployee" table="PermanentEmployees">
<property name="allowance" />
<property name="noOfLeaves" />
</union-subclass>
</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>
<!-- Database connection settings -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:xe</property>
<property name="connection.username">ranga</property>
<property name="connection.password">ranga</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<mapping resource="com/ranga/mapping/Person.hbm.xml" />
</session-factory>
</hibernate-configuration>
HibernateUtil.java
=======================
package com.ranga.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
private static final ServiceRegistry serviceRegistry;
static {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(
configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void closeSessionFactory() {
if (sessionFactory != null)
sessionFactory.close();
}
}
App.java
======================
package com.ranga;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.ranga.mapping.Employee;
import com.ranga.mapping.PermanentEmployee;
import com.ranga.mapping.Person;
import com.ranga.util.HibernateUtil;
public class App
{
public static void main( String[] args )
{
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Person p1= new Person();
p1.setId(1);
p1.setFirstName("ranga");
p1.setLastName("reddy");
p1.setAge(25);
Employee e1= new Employee();
e1.setId(2);
e1.setFirstName("raja");
e1.setLastName("reddy");
e1.setAge(45);
e1.setDesignation("Project Lead");
e1.setSalary(120000.0);
PermanentEmployee pe1= new PermanentEmployee();
pe1.setId(3);
pe1.setFirstName("vasundra");
pe1.setLastName("reddy");
pe1.setAge(40);
pe1.setDesignation("Architect");
pe1.setSalary(150000.0);
pe1.setNoOfLeaves(15);
pe1.setAllowance(5000.00);
session.save(p1);
session.save(e1);
session.save(pe1);
session.getTransaction().commit();
}
}
[all common attributes will be duplicated]
Advantage:
Disadvantage:
if you have a query against the super class, you will have to query several times for each sub-class tables.
Change in super class properties will have to be reflected in changes in each sub-class tables.
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.
Note: In this case there no need for the discriminator column because all entity has own table.