Sunday, 6 October 2013

Hibernate Mapping Strategy :Table per subclass

Hibernate Mapping Strategy :Table per subclass 

As the name suggest, we have table define for each class(abstract, interface or concrete).

Example :



As in this Example, we have one superclass Employee and 2 subclass PermanentEmployee and ContractEmployee. At the database level, we have 3 tables Employee, PermanentEmployee and ContractEmployee. Here Primary key of Employee table acts as both primary key and foreign key for PermanentEmployee and ContractEmployee tables.

Java Class :

Employee.java
package com.demo.example1.pojo;

public class Employee {

private String name;
private String email;
private Long empId;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Long getEmpId() {
return empId;
}
public void setEmpId(Long empId) {
this.empId = empId;
}
}

PermanentEmployee.java
package com.demo.example1.pojo;

import java.util.Date;

public class PermanentEmployee extends Employee {
private String designation;
private Date joiningDate;
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}

public Date getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Date joiningDate) {
this.joiningDate = joiningDate;
}

}


ContractEmployee.java
package com.demo.example1.pojo;

import java.util.Date;

public class ContractEmployee extends Employee {
private Date contractDate;

public Date getContractDate() {
return contractDate;
}

public void setContractDate(Date contractDate) {
this.contractDate = contractDate;
}
}


hbm file : 
<hibernate-mapping package="com.demo.example1.pojo">
<class name="Employee" table="employee">
<id name="empId" column="empId" type="long">
<generator class="identity"/>
</id>
<property name="name" column="name" type="string"></property>
<property name="email" column="email"  type="string" ></property>
<joined-subclass name="PermanentEmployee" table="PermanentEmployee" >
<key column="perm_emp_id"/>
<property name="designation" column="designation" />
<property name="joiningDate" column="joiningDate" type="timestamp" />
</joined-subclass>
<joined-subclass name="ContractEmployee" table="ContractEmployee">
<key column="contract_emp_id"/>
<property name="contractDate" column="contractDate" type="timestamp" />
</joined-subclass>
</class>
</hibernate-mapping>

Main Class :

package com.demo.example1;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.demo.example1.pojo.ContractEmployee;
import com.demo.example1.pojo.Employee;
import com.demo.example1.pojo.PermanentEmployee;


public class Test {
public static void main(String[] args) {
// First unit of work
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
PermanentEmployee pm = new PermanentEmployee();
pm.setDesignation("perm_desg") ;
pm.setEmail("simon@test.com");
pm.setName("Simon") ;
session.save(pm);
ContractEmployee cm = new ContractEmployee();
cm.setEmail("nathen@test.com");
cm.setName("Nathen") ;
session.save(cm) ;
List<Employee> em = session.createQuery("from Employee").list();
System.out.println(em.size());
tx.commit();
session.close();
HibernateUtil.shutdown();
}
}

Output : 

Hibernate: 
    /* insert com.demo.example1.pojo.PermanentEmployee
        */ insert 
        into
            employee
            (name, email) 
        values
            (?, ?)
Hibernate: 
    /* insert com.demo.example1.pojo.PermanentEmployee
        */ insert 
        into
            PermanentEmployee
            (designation, joiningDate, perm_emp_id) 
        values
            (?, ?, ?)
Hibernate: 
    /* insert com.demo.example1.pojo.ContractEmployee
        */ insert 
        into
            employee
            (name, email) 
        values
            (?, ?)
Hibernate: 
    /* insert com.demo.example1.pojo.ContractEmployee
        */ insert 
        into
            ContractEmployee
            (contractDate, contract_emp_id) 
        values
            (?, ?)
Hibernate: 
    /* 
from
    Employee */ select
        employee0_.empId as empId1_,
        employee0_.name as name1_,
        employee0_.email as email1_,
        employee0_1_.designation as designat2_2_,
        employee0_1_.joiningDate as joiningD3_2_,
        employee0_2_.contractDate as contract2_3_,
        case 
            when employee0_1_.perm_emp_id is not null then 1 
            when employee0_2_.contract_emp_id is not null then 2 
            when employee0_.empId is not null then 0 
        end as clazz_ 
    from
        employee employee0_ 
    left outer join
        PermanentEmployee employee0_1_ 
            on employee0_.empId=employee0_1_.perm_emp_id 
    left outer join
        ContractEmployee employee0_2_ 
            on employee0_.empId=employee0_2_.contract_emp_id
2


Advantage : 

  1. The SQL schema is Normalized.
  2. A polymorphic association to a particular subclass is represented as a foreign key referencing the table of that subclass 

Disadvantage : 

  1. Relies on outer join when querying for Employee class as shown in output .


No comments:

Post a Comment