Search This Blog

Wednesday 28 September 2011

The Hibernate Inheritance Mechanism - 1

Table per Concrete Class + Implicit Polymorphism
 This is the technique with minimum development efforts. The technique follows the below simple steps:
  1. For each concrete class, one table is created. 
  2. All the inherited properties are mapped in each of these tables.
  3. The abstract (base) class is not represented in SQL
So as per our schema we have now two tables CRICKETER and  FOOTBALLER
The mapping files for the two tables is as below
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.inheritance.model">
    <class name="Cricketer" table="CRICKETER">
        <id name="id" type="long">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="string">
            <column name="NAME" />
        </property>

        <property name="runs" type="integer">
            <column name="RUNS" />
        </property>
        <property name="wickets" type="integer">
            <column name="WICKETS" />
        </property>
        <property name="t20Player" type="boolean">
            <column name="T20_PLAYER" />
        </property>

    </class>
</hibernate-mapping> 
 

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.inheritance.model">
    <class name="Footballer" table="FOOTBALLER">
        <id name="id" type="long">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="string">
            <column name="NAME" />
        </property>

        <property name="goals" type="integer">
            <column name="GOALS" />
        </property>
        <property name="appearances" type="integer">
            <column name="APPEARANCES" />
        </property>
        <property name="sendOffs" type="integer">
            <column name="SEND_OFFS" />
        </property>

    </class>
</hibernate-mapping> 


The code on start up worked as normal, generating queries for both tables separately. Hibernate treated them just like any other mapping. Inserts of records in both tables were also the same.

Though it is very simple and easy, there exist certain problems with this approach:
  1. Implementation of polymorphic associations: If we have to map the relation between Team and Sportsperson ( 1 team has many sportsperson) then we need to create a foreign key Team_Id in both the above tables. Similarly if we need to map relation between the players and fans (1 player has many fans) then the fan table would have to have two columns - CRICKETER_ID and FOOTBALL_ID. As number of such subclasses increase the columns will also increase.
  2. Execution of polymorphic queries:It is not possible to retrieve the values of all Sportsperson by direct query. Instead this can only be done via multiple select queries - one for Cricketers and one for footballers. I tried the same
    public static void getAllSportsPerson() {
        Session session = sessionFactory.openSession();
        try {//THIS WILL NEVER WORK
            Query query = session.createQuery("from SportsPerson");
            System.out.println("Total Records : " + query.list().size());
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
    
    The logs indicate the failure:
    org.hibernate.hql.ast.QuerySyntaxException: SportsPerson is not mapped [from Spo
    rtsPerson]
        at org.hibernate.hql.ast.util.SessionFactoryHelper.requireClassPersister(Sessio
    nFactoryHelper.java:158)
        at org.hibernate.hql.ast.tree.FromElementFactory.addFromElement(FromElementFact
    ory.java:87)
        at org.hibernate.hql.ast.tree.FromClause.addFromElement(FromClause.java:70)
        at org.hibernate.hql.ast.HqlSqlWalker.createFromElement(HqlSqlWalker.java:255)
        at org.hibernate.hql.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3
    

  3. Property duplication: The name property which was inherited by both sub-classes now must be duplicated in both the created tables. Similarly, if we decide to add another attribute (e.g. date_of_birth) this would be a change in all the tables representing the sub-classes.

Update: For a brief summary of the Hibernate Inheritance types check this post.

No comments:

Post a Comment