Lesser-Known NHibernate Features: Versioning and Optimistic Concurrency

NHibernate supports the notion of entity version. An entity version is the value of some entity property that is mapped as versioned. There are several strategies for versioning:

  • A numeric counter;
  • The current (UTC) timestamp;
  • The current database timestamp;
  • The system elapsed ticks (DateTime.Ticks);
  • A database-specific row version (ROWVERSION in SQL Server, ORA_ROWSCN in Oracle, etc).

We map a version property as this:

public class VersionedEntity
{
    public int Id { get; protected set; }
    public int Version { get; protected set; }
}
 
public class VersionedEntityClassMapping<VersionedEntity>
{
    public VersionedEntityClassMapping()
    {
        this.Id(x => x.Id, x => x.Generator(Generators.Identity));
        this.Version(x => x.Version, x => x.Type(NHibernateUtil.Int32));
        //etc
    }
}

If you wish to use a strategy other than auto-incrementing versioning, just replace NHibernateUtil.Int32 by another instance of a class implementing IVersionType, such as NHibernateUtil.Ticks, NHibernateUtil.Timestamp, NHibernateUtil.UtcDateTime, NHibernateUtil.DbTimestamp, NHibernateUtil.Binary (for SQL Server), or a similar one – or roll out your own strategy.

Close to the notion of versioning comes optimistic concurrency. Using optimistic concurrency control, when a record is about to be updated, it is checked against a pre-saved value or set of values (the version), together with its primary key. If it doesn’t match, the number of affected records will be 0 instead of 1, and we know something went wrong: because the primary key doesn’t change, then it has to be the version:

UPDATE some_table
SET some_column = @p1
WHERE id = @p2
AND version = @p3

Optimistic concurrency can use:

  • The version property (if any), the default;
  • All of the entity’s properties;
  • All the dirty properties.

We just need to tell NHibernate which strategy we want to use:

public class VersionedEntityClassMapping<VersionedEntity>
{
    public VersionedEntityClassMapping()
    {
        this.Id(x => x.Id, x => x.Generator(Generators.Identity));
        this.Version(x => x.Version, x => x.Type(NHibernateUtil.Int32));
        this.OptimisticLock(OptimisticLockMode.Version); //NHibernate 4.1 only, no need to specify since this is the default
        //etc
    }
}

And that’s it. Happy versioning!

                             

No Comments

Add a Comment

As it will appear on the website

Not displayed

Your website