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;
}
}
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
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;
}
}
<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 :
- When defining properties in hbm file, make sure that discriminator is defined before we define any property element.
- 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:
- This mapping is a winner in terms of both performance and simplicity. It's the best performing way to represent polymorphism.
- There is no complex join or subselects required which makes ad-hoc reporting possible.
Disadvantage :
- 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.
- Voilates third normal form.
No comments:
Post a Comment