Managing Hibernate logical deletes

Recently we discovered a need to apply a “logical delete” on our business entities to avoid screwing up history details and to leave the audit trail intact. “Logical delete” means “mark deleted” instead of issuing physical sql DELETE update.

To implement logical delete on hibernate (3.3.2) you’ll basically need the following ingredients:

  • add @SQLDelete for your entity to update an existing column (property)
  • (optional) setup a filter to filter out all your logically deleted by default, rig @Filter to your entity

After this your Session#delete(Object) will only update the field and if you added the @Filter and apply it your searches (note, not primaryKey loads or gets) will not return the logically deleted.

If by now you have extensive unit tests, which test the behavior on your entity’s relations, you might have noticed that Collections owned by your entity are all deleted. This is because Hibernate does not know whether your @SQLDelete updated or deleted the row, and assumes that it was deleted.

To fix that, you need to roll your own CollectionPersister, most likely by extending
org.hibernate.persister.collection.BasicCollectionPersister. The important method here is #remove(Serializable, SessionImplementor) and it will be called:

  • when the owner entity has been deleted and org.hibernate.event.def.DefaultFlushEntityEventListener notices this
  • when the collection has become empty while it wasn’t previously

Latter point means that just overriding the #remove(..) with empty method will not allow the collections using this persisted be cleared after they have been persisted with at least one entity.

To fix this you need to call super.remove(..) when the owner’s org.hibernate.engine.EntityEntry#getStatus() != org.hibernate.engine.Status.DELETED.

You can find the owner through SessionImplementor#getPersistenceContext()‘s #getCollectionOwner(id, this) and get it’s EntityEntry through PersistenceContext#getEntry(Object).

Add the @Persister(impl=YourCollectionPersister.class) for each of your collections you’d like prevent from being deleted and that’s done.

If you’d like to see built-in logical delete support in hibernate go and share your opinions at HHH-6072.

Advertisements

One Comment

  1. Posted 2011-08-05 at 09:53 | Permalink | Reply

    Seeing that this one still gets views you probably before starting to implement anything described above should go and read Udi Dahan’s article “Don’t Delete – Just Don’t” at http://www.udidahan.com/2009/09/01/dont-delete-just-dont/.

    Dahan basically calls out for modelling the entity lifecycle INTO the entity rather than playing around with tricks like logical deletes. By lifecycle I mean the fact that if you want “soft deletes” your entity has actually a lifecycle step “being cancelled/deactivated” which probably should be part of the domain object, not just a column in database.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: