Mark entity as deleted using Hibernate Discriminator.

 

MSc. Rigre Gregorio Garciandía Sóñora

 

Problem

 

“You have in your system a business rule that specify that one entity is deleted physically from the DB and now this rule change and the application need to keep this entity for a future use”

 

Many times as a programmer I experimented business change when an user decide that he need to keep the deleted entities in the system for auditory or any other reason, suppose that the client want to keep the entity as is (not in auditory table).

 

There are many manners to encourage this issue, I’ll mention some of these strategies but aren’t in the scope of these document to mention all the possibilities:

 

1.      Create another table with the same structure of the original and move all the deleted entities for this new table. This is useful but in the system if many entities support these behaviour you need to duplicate a lot of tables and maintain all at the same time.

2.      Introduce a field in the table that indicate the state of the entity, in our case we can use the values “ACTIVE” and “DELETED” as a self explained values of the state of our entity. This is useful solution that you need to take in care, for sure you also need to consider the amount of data that you store in this table and evaluate a possible down of the system performance if the size of this table is too big.

3.      Any other.

 

In our sample I’ll consider the second option, so suppose that you decide that the best strategy for your system is to introduce a new fields in the entity that indicate if is ACTIVE or DELETE.

 

For sure you need to analyze the cost to made the changes in the system due these mean that now you need to change all the queries (HSQL or Criteria in Hibernate) to filter this entity by the “ACTIVE” value. This change can be very stressful and dangerous due you can introduce a lot of problems in your system.

 

Forces

 

 

Solution

 

Before start is important to take in care that this pattern is useful also with any other tool like hibernate and also that you can use the same pattern in many cases, not only to remove an entity but change the entity type etc etc, in fact I use this pattern in other cases but this is out of the scope of this document.

 

For this problem, and if you are use Hibernate (you can implement the same with any other tool but you need to found the way), I found a simple very effective solution using the “Table per class hierarchy” Hibernate Strategy.

 

The solution is very simple and the basic steps are described as:

 

1.      Generalize the entire behaviour of your class in a common class.

 

Keep only in your class the default constructor and any other method that you want to include. I my case I just leave only the constructor.

 

2.      Create another child class of the created common class

 

This class will be useful to “mark” as deleted the original entity. As a pattern I use the Prefix Deleted plus the original name of the class but you can use any name.

 

3.      Configure your hibernate mapping (or annotation) to support for this entity “Table per class hierarchy” Hibernate Strategy.

 

In this case is very useful if in you design you take in care to make an interface of any of the mapped hibernate POJO classes, due now you need to use this interface of the object that you want to modify. I use always an interface of any POJO that I serialize with Hibernate and all my services and logic always work with this interface as this manner I separate the business of the real entity managed by Hibernate.

 

4.      Use one discriminator field to specify the type of the class.

 

5.      Implement a DAO that change the class discriminator.

 

Note here that you can’t do that using hibernate, instead you need to use JDBC of any other manner to access directly to the discriminator field.

 

6.      Change the implementation of the method in the DAO that delete the entity and now just change the discriminator of the current entity for the discriminator of target entity that you select to represent the deleted entity.

 

One that you have this refactoring, the application can run without any problem and you don’t need to touch any other part of the code, the solution is very simple but as you can see required that you follow some pattern in the implementation of your system. I you don’t follow this pattern the solution is useful too but for sure maybe you need to change more parts of your application and made some refactoring before apply this pattern.

 

Strategies

 

For a better understanding of the matter I’ll explain the issue with a sample. Suppose that you have an invoicing application and any time that the clients cancel an order the system remove this order physically form the DB, now you want to keep this order in the system after the application user “delete” the cancelled order.

 

Suppose that you have the following implementation of the order

 

 

 

Just to simplify the sample I put only one field in the Order class, also is suppose that you will have an ID field, hash and equal method in this class (In my application I’ve an special class for all the entities that implement this issues, maybe some day I’ll write  pattern with this ;)).

 

Suppose also that you have the assessor’s method in the interface and in the class (in our sample something like getCreationDate and setCreationDate). I also assume that you use in the system the interface IOrder to get access to the Order class, only the DAO known that the instance of the entity is the Order class, the system work with IOrder interface.

 

Now all that we need is to generalize the Order class in a common class with the whole behaviour of the class Order, we’ll call to this class AbstractOrder. Also we’ll create another class named DeletedOrder that will represent the deleted entity (in our sample the order). The new structure looks like this.

 

At this point the system don’t suffer any major change, you can run you application without any problem.

 

The next step is to change hibernate mapping file (or the annotations if you are using Hibernate annotation). Suppose that we have something like this.

 

<hibernate-mapping>

   <class name="...Order" table="tbl_order" ...>

      <id name="id" column="ID" type="long" ...>

         ...

      </id>

      <version column="VERSION"... />

      <property name="creationDateDate" column="CREATION_DATE" ... />

   </class>

</hibernate-mapping>

 

Now we need to make some modification to this mapping to support the new behaviour, for that we need to:

 

1.      Change the class by the interface

 

At this point maybe you have the interface there due you are currently using the “Table per class hierarchy” Hibernate Strategy, I suppose that you aren’t using this strategy for the class that you want to change, if you are using this hibernate strategy you need to make different changes but the idea is the same.

 

2.      Introduce a discriminator

 

You need to introduce a discriminator field to configure the discriminators that you will use for the subclasses.

 

3.      Introduce a new field in the DB

 

In our case I’ll use the name TYPE for this field and is useful that you use the same field name for all the discriminators is all the tables that you have in the system, in this document I’ll implement a generic manner to change the discriminator and I’ll assume that the name of the database field is always “TYPE”

 

4.      Declare the two child classes with the corresponding discriminator values (Order and DeletedOrder).

 

You need to introduce the subclasses of the interface, at this point the system is suppose that continue running without any problem.

 

5.      Run and UPDATE script that set the value of the TYPE DB field, in this case is suppose that all the orders that you have are active so you must set this field value to the corresponding field discriminator.

 

After this changes the new mapping file must look something like this.

 

<hibernate-mapping>

   <class name="...IOrder" table="tbl_order" ...>

      <id name="id" column="ID" type="long" ...>

         ...

      </id>

 

      <discriminator column="TYPE" type="string" />

 

      <version column="VERSION"... />

      <property name="creationDateDate" column="CREATION_DATE" ... />

     

      <subclass name="...Order" discriminator-value="ACTIVE" .../>

      <subclass name="...DeletedOrder" discriminator-value="DELETED" .../>

 

   </class>

</hibernate-mapping>

 

Maybe you need to specify a proxy class (that could be the IOrder interface) for the subclasses, this depend of you necessity, I don’t will explain nothing about the other attributes that you need to use in Hibernate mapping file.

 

At this point you can run the application and for sure the application will be executed without any problem.

 

Now we need to implement some mechanism to change the discriminator, many people can think that is better to implement a copy constructor in the class DeletedOrder and when you try to delete the Order just copy all the fields to the DeletedOrder, remove physically the Order from the DB and save a new DeletedObject, this isn’t the idea that I want to expose due this option have many problems such as:

 

1.      You need to take in care that this entity could be related with many other entities (in our case maybe a good sample is a possible entity named OrderLineItem).

2.      Maybe you want to delete many entities and the process to remove one entity and save another could be slowly.

 

The idea is just to change the discriminator value directly form the DB (field tbl_table.TYPE). To do that I create a DAO class named DiscriminatorChangeDAO (and the corresponding interface named IDiscriminatorChangeDAO). The behaviour of this DAO is basically to receive the ID of the entity that you want to change and the destination class of the entity owner of this ID.

 

In the DAO we have two maps named “tables” and “discriminators”. In the “tables” map we must store the name of the destination class as a key and the name of the DB table as value, and in “discriminators” we must store the name of the destination class as a key and the name of the new discriminator value. The best option to use this class is with spring where you can inject the value of this fields using IoC, note that this class is prepared to receive a DataSource injected, if you forget that for sure you will experimented a NPE exception.

 

The class look like this:

 

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.SQLException;

import java.text.MessageFormat;

import java.util.HashMap;

import java.util.Map;

 

import javax.sql.DataSource;

 

import org.springframework.dao.DataAccessException;

import org.springframework.jdbc.core.ConnectionCallback;

import org.springframework.jdbc.core.JdbcTemplate;

 

import ...IDiscriminatorChangeDAO;

import ...IPersistent;

import ...DAOException;

 

/**

 * @author Rigre G. Garciandia Sonora

 */

public class DiscriminatorChangeDAO implements IDiscriminatorChangeDAO {

 

    private static final String UPDATE_TBL_SET_TYPE = "UPDATE {0} SET TYPE = ? WHERE ID = ?"; //$NON-NLS-1$

 

    private JdbcTemplate jdbcTemplate;

 

    private Map<Class<? >, String> tables = new HashMap<Class<?>, String>();

    private Map<Class<?>, String> discriminators = new

HashMap<Class<?>, String>();

 

    public void convertToInstanceOfType(final long id, final Class<? extends IPersistent>

clazz) throws DAOException {

 

        try {

            this.jdbcTemplate.execute(new ConnectionCallback() {

 

                public Object doInConnection(Connection connection) throws SQLException,

DataAccessException {

 

                    PreparedStatement prepareStatement =

connection.prepareStatement(MessageFormat.format(UPDATE_TBL

_SET_TYPE,

DiscriminatorChangeDAO.this.tables.get(clazz)));

 

                    prepareStatement.setString(1,

DiscriminatorChangeDAO.this.discriminators.get(clazz));

prepareStatement.setLong(2, id);

 

prepareStatement.executeUpdate();

 

                    return null;

                }

 

            });

 

            clear();

        }

        catch (Throwable t) {

            throw createDAOException(t);

        }

    }

 

    public void setDataSource(DataSource dataSource) {

 

        this.jdbcTemplate = new JdbcTemplate(dataSource);

    }

 

    public Map<Class<? extends IPersistent>, String> getDiscriminators() {

 

        return this.discriminators;

    }

 

    public void setDiscriminators(Map<Class<? extends IPersistent>, String>

discriminators) {

 

        this.discriminators = discriminators;

    }

 

    public Map<Class<? extends IPersistent>, String> getTables() {

 

        return this.tables;

    }

 

    public void setTables(Map<Class<? extends IPersistent>, String> tables) {

 

        this.tables = tables;

    }

}

 

Note that I assume that the name of the discriminator field always will be named as “TYPE”.

 

Now using spring you can configure this class as this manner:

 

<bean class="com.opnworks.aocb.sirene.dao.hibernate.DiscriminatorChangeDAO">

       <property name="discriminators">

              <props>

                     <!--Name of the target class mapped the new discriminator-->

                     <prop key="...DeletedOrder">DELETED</prop>

                     ...

              </props>

       </property>

       <property name="tables">

              <props>

                     <!--Name of the target class mapped the entity-->

                     <prop key="...DeletedOrder">tbl_order</prop>

              </props>

       </property>

       <property name="dataSource" ref="some data source" />

</bean>

 

 

Now all is ready to use our class, maybe we can implement this class using hibernate to get the mapped name of the table but this is out of the scope of this article, for the moment we need to map the table named as I expose here.

 

The next step is to demonstrate how we can use this class, suppose that we have  OrderDAO that have a method deleted inside, something like this:

 

public class OrderDAO extends HibernateDaoSupport implements IOrderDAO {

 

 

    public void deleteOrder (IOrder order) throws DAOException {

 

        try {

            getSession().delete(order);

        }

        catch (Throwable throwable) {

            throw new DAOException(throwable);

        }

    }

}

 

All that we need to do is to inject to this DAO the discriminator change DAO and use the method to change the discriminator value, after the refactoring the class OrderDAO look like this:

 

public class OrderDAO extends HibernateDaoSupport implements IOrderDAO {

 

    private IDiscriminatorChangeDAO discriminatorChangeDAO;

 

    public void deleteOrder (IOrder order) throws DAOException {

 

        try {

            this.discriminatorChangeDAO.convertToInstanceOfType(order.getId(),

                DeletedOrder.class);

        }

        catch (Throwable throwable) {

            throw new DAOException(throwable);

        }

    }

}

 

With this change the new remove method just change the discriminator for the order entity, you need to pay attention here due is possible that you experimented problems if you try to use in this session the instance of order, the best that you can do is to make a clean in the Hibernate session and be sure that this instance isn’t using anymore after the call to the deleteOrder method.

 

Related patterns

  1. IoC.
  2. DAO

 

Conclusion

 

For my daily work this pattern is very useful, in fact I use this pattern in other situations different to mark as deleted an entity, I think that you can apply this behaviour in many situations depending of the business logic that you have. You need to pay special attention if you want to apply this pattern to another context, remember that you are changing the discriminator of a entity and this mean that you in fact are change the entity type, if the new entity isn’t compatible with the previous entity you must experimented seriously problems in you system.

 

Also you need to take in care what happen in your system with concurrent access, in the applications that I use this pattern this issue isn’t important but maybe this isn’t your case.

 

At the end I want to apologize with any body that really read my document, I write this idea in one shoot and I don’t have a time to take a look to the orthography and redaction, in fact my English is too bad. I hope that this document in some manner help to your daily work but for sure isn’t useful to learn English ;).