One of the key object/relational paradigm mismatch concerns is replicating
"IS-A" relationship (inheritance) from the domain model to a DB schema. For
example, in Java, we implement type inheritance using superclasses and
subclasses. However, SQL doesn't provide support for supertables and subtables.
Hibernate, an Open Source Object Relational Mapping (ORM) solution can bridge
this gap between the relation and the domain object world. This article
continues from the December 2007 issue where we explored the "Table per class
hierarchy" strategy. In this article, we'll examine yet another inheritance
mapping strategy provided by Hibernate-Table per subclass. Note that we'll
continue using the same MedTracker application for demonstration.
Direct Hit! |
Applies To: Adv Java developers USP: Map each class from the domain inheritance tree to a separate database table Primary Link: www.hibernate.org/hib docs/reference/en/html/inheritance.html Keywords: Hibernate Inheritance Mappings |
Table per sub-class approach
As the name suggests, in “table per sub-class” approach, there exists one
table per class in the underlying database. Note that there will be a table
created even for abstract classes and interfaces. The "table per subclass"
approach represents inheritance relationships as foreign key associations. Each
table corresponding to a subclass has a primary key association to the
superclass table. Besides the primary key association, the tables here contain
columns only for non-inherited properties of the class. This approach is quite
different from the "table per class hierarchy" approach, wherein, the DB schema
has one table which represents all properties in the inheritance tree, apart
from a discriminator column.
As an illustration, consider the following code snippet which walks through
with the mapping file used to implement table per subclass strategy (for
brevity, the entire code is not shown).
As shown in the preceding code snippet, Hibernate uses the direct field
access strategy mechanism. This means that you don't have to get into the mess
of providing a getter/setter for every persistent property in the entity class.
Hibernate can directly access private fields using the Reflection API. As shown,
the
table. The
table. According to the Hibernate reference, it's used to define the foreign key
in the joined table, which references the primary key of the original table. The
complete source code is available on the CD.
The main benefit of this strategy is that the schema is normalized. Also,
note that unlike the "table per class hierarchy" strategy we don't require an
additional discriminator column. However, queries always require join across
tables which can reduce performance.
Client application
The client code is simple: we'll use a static singleton to startup Hibernate.
The startup includes building a global SessionFactory object. A SessionFactory
can open up new Sessions. A Session represents a single-threaded unit of work;
and the SessionFactory is a thread-safe global object, instantiated once.
Session session =
HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person p=new Employee("Satish","Sharma","Male",26,"Common Cold",new
java.util.Date(),new Long(1));
session.save(p);
session.getTransaction().commit();
}
The output after executing the client application is shown in Listing 2 below
(for brevity, not all log messages are shown).
create table EMPLOYEE (PERSON_ID bigint not null,
POLICY_NO bigint, primary key (PERSON_ID))
create table PATIENT (PERSON_ID bigint not null, DIAGNOSIS varchar(255),
DATE_OF_ADMISSION datetime, primary key (PERSON_ID))
create table PERSON (PERSON_ID bigint not null auto_increment, F_NAME
varchar(255), L_NAME varchar(255), GENDER varchar(255), AGE integer, primary key
(PERSON_ID))
alter table EMPLOYEE add index FK75C8D6AEA857FAF4 (PERSON_ID), add constraint
FK75C8D6AEA857FAF4 foreign key (PERSON_ID) references PERSON (PERSON_ID)
alter table PATIENT add index FKFB9F76E5A857FAF4 (PERSON_ID), add constraint
FKFB9F76E5A857FAF4 foreign key (PERSON_ID) references PERSON (PERSON_ID)
schema export complete
Hibernate: insert into PERSON (F_NAME, L_NAME, GENDER, AGE) values (?, ?, ?, ?)
Hibernate: insert into EMPLOYEE (POLICY_NO, PERSON_ID) values (?, ?)
As discussed, Hibernate's hbm2ddl.auto DB schema generator tool will create
three tables, one for each class in the domain model. Furthermore, as shown
above, each subclass table has a primary key association to the superclass table
(PERSON).
Conclusion
Hibernate inheritance strategies bridge the gap between DBAs and Java
developers by providing an easy and seamless way of replicating Java "IS-A"
relationship to underlying database tables. JPA, an EJB 3.0 sub-specification
borrows these concepts from Hibernate to map entities to database tables.