Hibernate Inheritance Table per SubClass
This tutorial explains Hibernate Inheritance Table per SubClass and an implementation of the same.
1. Introduction
Java is an Object Oriented Language and supports Inheritance which is one of the most visible paradigms of Object-Relational mismatch. Object Oriented Systems can model both “is a”and “has a” relationship whereas Relational Model supports only “has a” relationship between two entities. Hibernate can help us map such Objects with relational tables.
Basically there are three ways in which we can implement Inheritance in Hibernate. We shall use one of the ways here Table per SubClass.
2. Example
Consider the below Object Model where in we have Base Class Payment and its subclasses OnlineTransfer, ChequePayment, CashPayment which are basically specific forms of Payments.
3. Database Table Design
In Table per Sub Class method, we create separate table for each subclass. Each Sub Class Table such as ONLINE_PAYMENT hold a foreign key reference to PAYMENT Table. The ER Diagram for this approach would look like this.
As we mentioned earlier all the Sub Tables hold FOREIGN KEY reference to PAYMENT Table.
4. Project Setup
Lets create a simple Maven project with the below pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.heapcode.hibernate</groupId> <artifactId>hibernate-basic</artifactId> <version>1.0</version> <packaging>pom</packaging> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.10.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> </dependencies> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project> |
In the above pom.xml we added dependencies for Hibernate 3.6.10, MySQL Connector 5.1.25, Javassist and Sl4J.
5. Database Table Creation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
CREATE TABLE `PAYMENT` ( `PAYMENT_ID_PK` int(11) NOT NULL AUTO_INCREMENT, `AMOUNT` decimal(10,2) NOT NULL, PRIMARY KEY (`PAYMENT_ID_PK`), UNIQUE KEY `PAYMENT_ID_PK_UNIQUE` (`PAYMENT_ID_PK`) ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=latin1$$; CREATE TABLE `CASH_PAYMENT` ( `CASH_PAYMENT_DATE` date NOT NULL, `PAYMENT_ID_FK` int(11) NOT NULL, KEY `FK_1_idx` (`PAYMENT_ID_FK`), CONSTRAINT `PAYMENT_ID_FK` FOREIGN KEY (`PAYMENT_ID_FK`) REFERENCES `PAYMENT` (`PAYMENT_ID_PK`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=latin1$$; CREATE TABLE `CHEQUE_PAYMENT` ( `CHEQUE_NO` varchar(12) NOT NULL, `CHEQUE_DATE` datetime NOT NULL, `PAYMENT_ID_FK` int(11) NOT NULL, KEY `CHEQUE_FK_PAYMENT_ID_PK_idx` (`PAYMENT_ID_FK`), CONSTRAINT `CHEQUE_FK_PAYMENT_ID_PK` FOREIGN KEY (`PAYMENT_ID_FK`) REFERENCES `PAYMENT` (`PAYMENT_ID_PK`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=latin1$$; CREATE TABLE `ONLINE_PAYMENT` ( `TRANSACTION_NO` varchar(12) NOT NULL, `PAYMENT_ID_FK` int(11) NOT NULL, UNIQUE KEY `TRANSACTION_NO_UNIQUE` (`TRANSACTION_NO`), KEY `ONLINE_PAYMENT_PAYMENT_ID_FK_idx` (`PAYMENT_ID_PK`), CONSTRAINT `ONLINE_PAYMENT_PAYMENT_ID_FK` FOREIGN KEY (`PAYMENT_ID_PK`) REFERENCES `PAYMENT` (`PAYMENT_ID_PK`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=latin1$$; |
6. Hibernate Entity Class & Hibernate Mapping File
Lets us create a Hibernate Entity Class for Payment.java, CashPayment.java, ChequePayment.java, OnlineTransfer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package com.heapcode.hibernate.entity; import java.io.Serializable; import java.math.BigDecimal; /** * @author Manjunath Sampath * */ public class Payment implements Serializable { private static final long serialVersionUID = -3443358305531045216L; private int paymentIdPk; private BigDecimal amount; public int getPaymentIdPk() { return paymentIdPk; } public void setPaymentIdPk(int paymentIdPk) { this.paymentIdPk = paymentIdPk; } public BigDecimal getAmount() { return amount; } public void setAmount(BigDecimal amount) { this.amount = amount; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.heapcode.hibernate.entity; import java.io.Serializable; import java.util.Date; /** * @author Manjunath Sampath * */ public class CashPayment extends Payment implements Serializable { private static final long serialVersionUID = -6796314329006612115L; private Date cashPaymentDate; public Date getCashPaymentDate() { return cashPaymentDate; } public void setCashPaymentDate(Date cashPaymentDate) { this.cashPaymentDate = cashPaymentDate; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package com.heapcode.hibernate.entity; import java.io.Serializable; import java.util.Date; /** * @author Manjunath Sampath * */ public class ChequePayment extends Payment implements Serializable { private static final long serialVersionUID = -8230545444283283149L; private String chequeNo; private Date chequeDate; public String getChequeNo() { return chequeNo; } public void setChequeNo(String chequeNo) { this.chequeNo = chequeNo; } public Date getChequeDate() { return chequeDate; } public void setChequeDate(Date chequeDate) { this.chequeDate = chequeDate; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.heapcode.hibernate.entity; import java.io.Serializable; /** * @author Manjunath Sampath * */ public class OnlineTransfer extends Payment implements Serializable { private static final long serialVersionUID = -3393095656907676523L; private String transactionNo; public String getTransactionNo() { return transactionNo; } public void setTransactionNo(String transactionNo) { this.transactionNo = transactionNo; } } |
and the Hibernate Mapping File Payment.hbm.xml as
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?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.heapcode.hibernate.entity"> <class name="Payment" table="PAYMENT" catalog="heapcode" discriminator-value="OTHERS"> <id name="paymentIdPk" type="java.lang.Integer"> <column name="PAYMENT_ID_PK" /> <generator class="identity" /> </id> <property name="amount" type="java.math.BigDecimal"> <column name="AMOUNT" precision="2" not-null="true" /> </property> <joined-subclass name="CashPayment" table="CASH_PAYMENT" extends="Payment"> <key column="PAYMENT_ID_FK"/> <property name="cashPaymentDate" type="java.util.Date" length="4" column="CASH_PAYMENT_DATE"/> </joined-subclass> <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT" extends="Payment"> <key column="PAYMENT_ID_FK"/> <property name="chequeNo" type="java.lang.String" length="45" column="CHEQUE_NO" /> <property name="chequeDate" type="java.util.Date" length="3" column="CHEQUE_DATE" /> </joined-subclass> <joined-subclass name="OnlineTransfer" table="ONLINE_PAYMENT" extends="Payment"> <key column="PAYMENT_ID_FK"/> <property name="transactionNo" type="java.lang.String" length="45" column="TRANSACTION_NO" /> </joined-subclass> </class> </hibernate-mapping> |
Note that we have defined only one hibernate mapping (hbm) file Payment.hbm.xml
. All the entities CashPayment,ChequePayment
and Employee
Entity classes are defined within the same mapping file as joined Sub Classes.
<joined-subclass> tag is used to map the subclasses of Payment. Note that we have not used the usual <class>
tag to map the subclasses as it is in the hierarchy tree.
7. Hibernate Configuration
Below is the Hibernate Configuration File hibernate.cfg.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.bytecode.use_reflection_optimizer">false</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/heapcode</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <mapping resource="Payment.hbm.xml"></mapping> </session-factory> </hibernate-configuration> |
7. Main Program
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package com.heapcode.hibernate.main; import java.math.BigDecimal; import java.util.Date; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import com.heapcode.hibernate.entity.CashPayment; import com.heapcode.hibernate.entity.ChequePayment; import com.heapcode.hibernate.entity.OnlineTransfer; import com.heapcode.hibernate.entity.Payment; /** * @author Manjunath Sampath * */ public class HibernateMain { public static void main( String[] args ){ SessionFactory sf = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory(); Session session = sf.openSession(); Payment payment = new Payment(); payment.setAmount(new BigDecimal(122.89)); CashPayment cashPayment = new CashPayment(); cashPayment.setAmount(new BigDecimal(872.98)); cashPayment.setCashDepositDate(new Date()); ChequePayment chequePayment = new ChequePayment(); chequePayment.setAmount(new BigDecimal(456.98)); chequePayment.setChequeNo("BCGD93939"); chequePayment.setChequeDate(new Date()); OnlineTransfer onlineTransfer = new OnlineTransfer(); onlineTransfer.setAmount(new BigDecimal(342.22)); onlineTransfer.setTransactionNo("NEFT22200222"); Transaction tx = null; try{ tx = session.getTransaction(); tx.begin(); session.persist(payment); session.persist(cashPayment); session.persist(chequePayment); session.persist(onlineTransfer); tx.commit(); }catch(RuntimeException re){ tx.rollback(); re.printStackTrace(); } session.close(); sf.close(); } } |
8. Output
From the above Console Output we could see that irrespective of whatever class we persist all the data is inserted into PAYMENT Table.
9. Project Structure
Download Hibernate Inheritance Table per SubClass Example
I hope this has been useful for you and I’d like to thank you for reading. If you like this article, please leave a helpful comment and share it with your friends.