Pages

Thursday, May 23, 2013

How to map a State Pattern in Hibernate

Hi, in this post I will show how to map a class hierarchy that represents an implementation of the State Design Pattern in Hibernate.

This solution only applies when you already know beforehand the possible states of the Context role of the state pattern, so no states will be added in the future; otherwise another aproach would be more suitable that involves developing custom hibernate UserTypes


Class Diagram


Here is the picture of the basic class diagram that we'll use for mapping:




Hibernate Mapping


The ApplicationState object is mapped to the following SQL Table:

CREATE TABLE [APPLICATION_STATE](
[id] [int] NOT NULL,
[description] [nvarchar](50) NULL,
 CONSTRAINT [PK_APPLICATION_STATE] PRIMARY KEY CLUSTERED 
(
[id] ASC
)
)


Taking into account what we said about the fixed states that the Application can have, we'll suppose that the APPLICATION_STATE table is already populated with data and it will be a read-only entity.

The mapping file showed in the listing below, beside the two properties of the table, also includes reference to the subclasses.
It uses the id stored in the APPLICATION_STATE table as a discriminator value to identify and determine the apropiate concrete subclass at runtime.

<hibernate-mapping>
<class name="com.foo.ApplicationState" table="APPLICATION_STATE" polymorphism="implicit">    
    <cache usage="read-only"/>    
    <id name="id" column="id">
       <generator class="assigned" />
    </id>
    <discriminator insert="false" column="id" />
    <property name="description" column="description" />
    <subclass name="com.foo.PendingApplication" discriminator-value="0"/>
    <subclass name="com.foo.ApprovedApplication" discriminator-value="1"/>
    <subclass name="com.foo.RejectedApplication" discriminator-value="2"/>
</class>
</hibernate-mapping>


The Application mapping refers to the state as a simple "many-to-one" property.

<hibernate-mapping>
<class name="com.foo.Application" table="APPLICATION">
    ...
    <many-to-one
        name="state" column="stateId"
  outer-join="false"
  lazy="false"
  not-found="ignore"
        class="com.foo.ApplicationState" >
    </many-to-one>
    ...
</class>
</hibernate-mapping>


So when you load the Application object, hibernate automatically grabs the according concrete ApplicationState subclass, based on the stateId stored in the APPLICATION table.

Hope this is clear enough, comment if you any question.


References

4 comments:

  1. Could you send me the complete sample code? I used your solution in my application but I'm receiving a Hibernate exception...

    ReplyDelete
  2. Argentina Bitcoins is focused on offering safe communications and repayments in between models online of Things. However a different one, Monero, is all about level of privacy, producing dealings between end users really anonymous and untraceable all over its block chain system.

    ReplyDelete