Class Table Inheritance Pattern

This pattern belongs to Object-Relational Structural Patterns Catalog and this Catalog belongs to Patterns of Enterprise Application Architecture.

Intent

Represents an inheritance hierarchy of classes with one table for each class.
Class Table Inheritance supports one database table per class in the inheritance structure.

Explanation


Please note in the diagram, each class have their own database table.

Player class have its own players database table.

Cricketer class have its own cricketers database table.

Footballer class have its own footballers database table.

Bowler class has its own bowlers database table.

How It Works

The straightforward thing about Class Table Inheritance is that it has one table per class in the domain model. The fields in the domain class map directly to fields in the corresponding tables. As with the other inheritance mappings the fundamental approach of Inheritance Mappers (302) applies.

The biggest implementation issue with Class Table Inheritance is how to bring the data back from multiple tables in an efficient manner. Obviously, making a call for each table isn�t good since you have multiple calls to the database. You can avoid this by doing a join across the various component tables; however, joins for more than three or four tables tend to be slow because of the way databases do their optimizations.

When to Use It

Class Table Inheritance, Single Table Inheritance and Concrete Table Inheritance are the three alternatives to consider for inheritance mapping.
The strengths of Class Table Inheritance are :
  • All columns are relevant for every row so tables are easier to understand and don�t waste space.
  • The relationship between the domain model and the database is very straightforward.
The weaknesses of Class Table Inheritance are :
  • You need to touch multiple tables to load an object, which means a join or multiple queries and sewing in memory.
  • Any refactoring of fields up or down the hierarchy causes database changes.
  • The supertype tables may become a bottleneck because they have to be accessed frequently.
  • The high normalization may make it hard to understand for ad hoc queries.
  • You don�t have to choose just one inheritance mapping pattern for one class hierarchy. You can use Class Table Inheritance for the classes at the top of the hierarchy and a bunch of Concrete Table Inheritance for those lower down.

Implementation

Hibernate ORM Framework provides  inheritance mapping strategies : Table Per Concrete class using Annotation
In case of table per concrete class, tables are created as per class. But the duplicate column is added in subclass tables.
In case of Table Per Concrete class, tables are created per class. So there are no nullable values in the table. Disadvantage of this approach is that duplicate columns are created in the subclass tables.
Here, we need to use @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) annotation in the parent class and @AttributeOverrides annotation in the subclasses.
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) specifies that we are using table per concrete class strategy. It should be specified in the parent class only.
@AttributeOverrides defines that parent class attributes will be overriden in this class. In table structure, parent class table columns will be added in the subclass table.
The class hierarchy is given below:
Create Hibernate model classes. we need to create the persistent classes representing the inheritance. Let's create the three classes for the above hierarchy:
import javax.persistence.*;  

@Entity
@Table(name = "employee102")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

public class Employee {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)

@Column(name = "id")
private int id;

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

//setters and getters
}
import javax.persistence.*;  

@Entity
@Table(name="regularemployee102")
@AttributeOverrides({
@AttributeOverride(name="id", column=@Column(name="id")),
@AttributeOverride(name="name", column=@Column(name="name"))
})
public class Regular_Employee extends Employee{

@Column(name="salary")
private float salary;

@Column(name="bonus")
private int bonus;

//setters and getters
}
import javax.persistence.*;  
@Entity
@Table(name="contractemployee102")
@AttributeOverrides({
@AttributeOverride(name="id", column=@Column(name="id")),
@AttributeOverride(name="name", column=@Column(name="name"))
})
public class Contract_Employee extends Employee{

@Column(name="pay_per_hour")
private float pay_per_hour;

@Column(name="contract_duration")
private String contract_duration;

public float getPay_per_hour() {
return pay_per_hour;
}
public void setPay_per_hour(float payPerHour) {
pay_per_hour = payPerHour;
}
public String getContract_duration() {
return contract_duration;
}
public void setContract_duration(String contractDuration) {
contract_duration = contractDuration;
}
}

Add mapping of hbm file in 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">

<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="hbm2ddl.auto">update</property>
<property name="dialect">org.hibernate.dialect.Oracle9Dialect</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:xe</property>
<property name="connection.username">system</property>
<property name="connection.password">oracle</property>
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

<mapping class="com.javatpoint.mypackage.Employee"/>
<mapping class="com.javatpoint.mypackage.Contract_Employee"/>
<mapping class="com.javatpoint.mypackage.Regular_Employee"/>
</session-factory>
</hibernate-configuration>

Create the class that stores the persistent object. In this class, we are simply storing the employee objects in the database.

File: StoreData.java
import org.hibernate.*;  
import org.hibernate.cfg.*;

public class StoreData {
public static void main(String[] args) {
AnnotationConfiguration cfg=new AnnotationConfiguration();
Session session=cfg.configure("hibernate.cfg.xml").buildSessionFactory().openSession();

Transaction t=session.beginTransaction();

Employee e1=new Employee();
e1.setName("sonoo");

Regular_Employee e2=new Regular_Employee();
e2.setName("Vivek Kumar");
e2.setSalary(50000);
e2.setBonus(5);

Contract_Employee e3=new Contract_Employee();
e3.setName("Arjun Kumar");
e3.setPay_per_hour(1000);
e3.setContract_duration("15 hours");

session.persist(e1);
session.persist(e2);
session.persist(e3);

t.commit();
session.close();
System.out.println("success");
}
}

References

Comments

Popular posts from this blog

Design Patterns used in Hibernate Framework

Data Mapper Pattern

Identity Map Pattern