Richard Neil Ilagan
Richard Neil Ilagan

Reputation: 14747

How do I "deactivate" an entity instead of deleting it using NHibernate?

I'm not so sure if this is really trivial to do and I'm just over-complicating stuff, but I've been thinking about this for the good part of the past hour or so.

So I have entities. Hence, NHibernate. What I want to do is to only "deactivate" entities whenever I want to "delete" them, instead of actually removing them physically from the database. (Just cause we don't want to be really deleting records from our data store).

All my entities inherit from a BaseEntity class with a BaseEntity.Active property.

What I've got running right now is something like the following in the entity class' mapping file:

<sql-delete>
UPDATE SomeEntityTable SET Active = 0 WHERE Id = ?
</sql-delete>

This works fine, except that I'll have to inject that, customized with the table name, into every single HBM mapping file for every single entity (we're not implementing the BaseEntity inheritance in any subclassing strategy).

As you can see, that can be a bit menial. The coding would be tedious, the maintenance horrendous, and declaring the table name twice in the same mapping file just rubs me the wrong way.

What I was playing around earlier was whether or not I could implement an event listener; perhaps OnPreDelete or something, and update the entity's .Active property, like so:

class BaseEventListener : IPreDeleteListener
{
    public bool OnPreDelete(PreDeleteEvent @event)
    {
        BaseEntity be = @event.Entity as BaseEntity;
        if (be != null) 
            be.Active = false;

        return false;
    }
}

That way, the whole "deactivation" thingy is automated for all entities that support deactivation.

The problem is, I'm thinking that NHibernate would still build a proper DELETE SQL query that will burn my entity from the data store anyway instead of updating the thing, so this'll just be wasted automagic effort.

How should I go about this?

Upvotes: 2

Views: 372

Answers (2)

Diego Mijelshon
Diego Mijelshon

Reputation: 52725

Since it's pretty clear that you never actually delete your persistent entities (as is the case with most applications), there's is no need to use the Delete method just because it's there.

An alternative approach:

  • Declare a base entity with an Active property
  • Set it to false for "delete" use cases. You can even add a Delete method to your base entity that does just that
  • You can, additionally, create a filter to avoid loading "deleted" entities

Yes, there is some work involved, but in the long run it's for the best, as you'll still have a maintainable, non-hacky implementation.

Some of the burden can be reduced if you use a code+convention-based mapping approach, like ConfORM or Fluent.

Upvotes: 2

Paco
Paco

Reputation: 8381

You can use an event listener. You have to add the listener to the configuration as well.

public class SoftDeleteEventListener : DefaultDeleteEventListener
    {
        protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities)
        {
            var softDeletable = entity as BaseEntity;
            if (softDeletable != null)
            {
                softDeletable.Active = false;
            }
            else
            {
                base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities);
            }
        }
    }

Upvotes: 3

Related Questions