Showing posts with label Hibernate Mapping Strategy. Show all posts
Showing posts with label Hibernate Mapping Strategy. Show all posts

Sunday, 6 October 2013

Mapping Class Inheritance in Hibernate

Hibernate has four different approach to represent an inheritance hierarchy.

  1. Table per concrete class with Implicit polymorphism : Use no explicit inheritance mapping and default runtime polymorphic behavior.
  2. Table per concrete class with unions : Discard polymorphism and inheritance relationship completely from the SQL schema
  3. Table per class hierarchy : Enable polymorphism by de-normalizing the SQL schema and utilizing a type discriminator column that holds that type information
  4. Table per subclass : Represent is a (inheritance) relationships as has a (foreign key) relationships. 


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 .


Hibernate Mapping Strategy : Table per class Hierachy

Table per class Hierachy :  As the name suggest, the entire class hierarchy (abstract, interface and concrete class) is mapped to a single table. This table includes columns for all the properties of all classes in the hierarchy and the concrete subclass represented by a particular row is identified by the value of a type discriminator column.

Example :



As in this example, we have 3 different java classes and all the properties are mapped to a single table employee. Apart from this, we have another column "emp_type" which acts as a discriminator between PermanentEmployee and ContractEmployee class.

Java Files :

Employee Class
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  Class : 

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  Class : 
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 files:
<hibernate-mapping package="com.demo.example1.pojo">
<class name="Employee" table="employee">

<id name="empId" column="empId" type="long">
<generator class="identity"/>
</id>

<discriminator column="emp_type" />

<property name="name" column="name" type="string"></property>
<property name="email" column="email"  type="string" ></property>


<subclass discriminator-value="pe" name="PermanentEmployee">
<property name="designation" column="designation" />
<property name="joiningDate" column="joiningDate" type="timestamp" />
</subclass>

<subclass discriminator-value="ce" name="ContractEmployee">
<property name="contractDate" column="contractDate" type="timestamp" />
</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("lead") ;
pm.setEmail("peter@test.com");
pm.setName("Peter") ;

session.save(pm);

ContractEmployee cm = new ContractEmployee();
cm.setEmail("simon@test.com");
cm.setName("Simon") ;
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_hie
            (name, email, designation, joiningDate, emp_type)
        values
            (?, ?, ?, ?, 'pe')
Hibernate:
    /* insert com.demo.example1.pojo.ContractEmployee
        */ insert
        into
            employee_hie
            (name, email, contractDate, emp_type)
        values
            (?, ?, ?, 'ce')
Hibernate:
    /*
from
    Employee */ select
        employee0_.empId as empId1_,
        employee0_.name as name1_,
        employee0_.email as email1_,
        employee0_.designation as designat5_1_,
        employee0_.joiningDate as joiningD6_1_,
        employee0_.contractDate as contract7_1_,
        employee0_.emp_type as emp2_1_
    from
        employee employee0_
2


Points to Note : 
  1. When defining properties in hbm file, make sure that discriminator is defined before we define any property element. 
  2. In case, if we dont have the freedom to add new discriminator column, we can apply a formula to calculate discriminator value for each row.
Example :
<discriminator formula="case when contractDate is not null then 'ce' else 'pe'  " />

Advantage: 
  1. This mapping is a winner in terms of both performance and simplicity. It's the best performing way to represent polymorphism.
  2. There is no complex join or subselects required which makes ad-hoc reporting possible.


Disadvantage :
  1. All properties declared by the subclass must be declared to be nullable. so loss of not null constraint may be serious problem from data integrity point of view.
  2. Voilates third normal form.


Saturday, 5 October 2013

Hibernate Mapping Strategy : Table Per Concrete Class with Unions

Table Per Concrete Class with Unions

Consider this Example :













As in this Example, we have an abstract class Employee which is inherited by 2 concrete class PermanentEmployee and ContractEmployee.  We have 2 tables PermanentEmployee and ContractEmployee to map this concrete class.

This mapping is very much similar to Table with Concrete class with implicit polymorphism hibernate mapping strategy except the fact that  in this strategy the database identifier is defined in abstract class which  is shared for by all concrete class in hierarchy.  Example Employee class has primary key "empId" which is shared by PermanentEmployee and ContractEmployee class.


Java Class :
Employee Class :
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;
}

}

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 files looks like :

<hibernate-mapping package="com.demo.example1.pojo">

<class  name="Employee" abstract="true">

<id name="empId" column="empId" type="long">
<generator class="assigned"/>
</id>

<property name="name" column="name" access="field" />
<property name="email" column="email" access="field" />

<union-subclass table="permanentemployee" name="PermanentEmployee">
<property name="designation" column="designation" />
<property name="joiningDate" column="joiningDate" type="timestamp" />
</union-subclass>

<union-subclass table="contractemployee" name="ContractEmployee">
<property name="contractDate" column="contractDate" type="timestamp" />
</union-subclass>

</class>
</hibernate-mapping>



To Run :
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.Message;
import com.demo.example1.pojo.PermanentEmployee;


public class Test {
public static void main(String[] args) {

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

PermanentEmployee pm = new PermanentEmployee();
pm.setDesignation("desg") ;
pm.setEmail("permEmployee@test.com");
pm.setName("Simon") ;
pm.setEmpId(1l);
session.save(pm);


ContractEmployee cm = new ContractEmployee();
cm.setEmail("contractEmployee@test.com");
cm.setName("Peter") ;
cm.setEmpId(2l);
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
            permanentemployee
            (name, email, designation, joiningDate, empId)
        values
            (?, ?, ?, ?, ?)
Hibernate:
    /* insert com.demo.example1.pojo.ContractEmployee
        */ insert
        into
            contractemployee
            (name, email, contractDate, empId)
        values
            (?, ?, ?, ?)
Hibernate:
    /*
from
    Employee */ select
        employee0_.empId as empId1_,
        employee0_.name as name1_,
        employee0_.email as email1_,
        employee0_.designation as designat1_2_,
        employee0_.joiningDate as joiningD2_2_,
        employee0_.contractDate as contract1_3_,
        employee0_.clazz_ as clazz_
    from
        ( select
            null as contractDate,
            joiningDate,
            empId,
            email,
            name,
            designation,
            1 as clazz_
        from
            permanentemployee
        union
        select
            contractDate,
            null as joiningDate,
            empId,
            email,
            name,
            null as designation,
            2 as clazz_
        from
            contractemployee
    ) employee0_
2


Points To Note :
  1. Employee class has been declared as abstract in hbm file. Otherwise a separate table for instance of the superclass is needed. Here in this example, "assigned" id generation strategy is used which allows us to manually set the id of the instance.
  2. We cannot use Native or identity or such id generate strategy when using this Hibernate Mapping Strategy. Reason is primary key is to be shared across all union subclass of hierarchy.


Friday, 4 October 2013

Hibernate Mapping Strategy : Table with Concrete class with implicit polymorphism.

Table with Concrete Class with Implicit Polymorphism :
As the name suggest, the polymorphic relationship is at java side while no such relationship exits on database layer.

Example :














As in the example,
We have a 3 seperate  java class - Employee, PermanentEmployee and ContractEmployee . Here Employee class is the super class of PermanentEmployee class and ContractEmployee class.

On the database side, we have just 2 tables. PermanentEmployee and ContractEmployee Table. As shown in the diagram, properties of Java Employee class is represented as columns in PermanentEmployee and ContractEmployee tables.

The mapping is also straightforward. since we have just 2 tables, we would have 2 hbm files, namely PermanentEmployee.hbm.xml and ContractEmployee.hbm.xml.

Points to Note: 
  1. Employee class in this example can be consider as an abstract class which shares some of the common properties between PermanentEmployee and ContractEmployee class. 
  2. Primary key is not shared by superclass. Each of the subclass has there own primary key.

Disadvantage of this approach:
  1. It doesn't support polymorphic relationship so well at database layer. Polymorphic relation are usually represented as foreign key relationship. If the subclass are mapped all mapped to different tables, a polymorphic association to their superclass cannot be represented as simple foreign key relationship.
  2. Since no polymorphic relationship exists for super class, a change in superclass would results in a change in all tables. Example, to add another property "department" in Employee class would results in change in PermanentEmployee and ContractEmployee Table and corresponding hbm files. 
  3. Polymorphic queries are also problematic.  Example, to query for all Employees with Email like '%some.com%', would be executed in multiple SQL SELECTS.
    • Select name, email from PermanentEmployee where  Email like '%some.com%' ;
    • Select name, email from ContractEmployeewhere  Email like '%some.com%' ;


When to Use :

  1. When implicit polymorphism is necessary when mapping legacy models where the tables do not share many common properties.
  2. This approach can also be used when modification to the superclass is highly unlikely in future.