August 13, 2012

Unique number counter system using SQL Server identity fields and Fluent NHibernate

Filed under: Development,NHibernate,SQL Server — Tags: , , — Darrin Maidlow @ 6:00 am

**UPDATE – As we moved forward with our project this method turned out to be a little less awesome than I thought when I put it together.   I’ve left this post here though as I am not ashamed of my failures! There is also some neat stuff in here with setting up the identity fields using nHibernate.

Recently I needed to create a generic re-usable system to generate system wide unique counters using SQL server tables and identity fields to handle the number generation.  One of the key requirements was to be able to specify the identity seed, but in a re-usable way of course.

Generic Class and Class Map

So lets start this off with a base class to define the counter object:

namespace GenericCounter
{
    /// <summary>
    /// Define the attributes of a generic counter 
    /// </summary>
    /// <remarks></remarks>
    /// <example>
    ///     <code>
    ///     </code>
    /// </example>
    public class CounterObject
    {
        private Int32? _counter;
        /// <summary>
        /// The unique key value distinguishing this counter object from all other instances of the same class.
        /// </summary>
        /// <remarks>NHibernate only allows one key per table and requires that a field be set as key.  It cannot be the Identity field</remarks>
        public virtual Guid ID { get; protected set; }
 
        /// <summary>
        /// Gets or sets the counter.
        /// </summary>
        /// <value>The counter value which will be generated by SQL server</value>
        /// <remarks></remarks>
        public virtual int? Counter {get { return _counter; } protected set { _counter = value; }}
    }
}

The first thing you will notice is that we’ve defined two fields.  One field guid and one field as  a nullable Int32.  Fluent NHibernate needs a key field for this table and to do the trickery that comes next it cannot be our identity based field.  Next lets setup a generic fluent mapping:

using System;
using FluentNHibernate.Mapping;
 
namespace GenericCounter.Mapping
{
    /// <summary>
    /// Generic class that provides Fluent nHibernate mappings for the CounterObjects
    /// </summary>
    /// <typeparam name="TEntity">The type of the entity.</typeparam>
    /// <remarks></remarks>
    public class CounterObjectMap<TEntity> : ClassMap<TEntity> where TEntity : CounterObject
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CounterObjectMap&lt;TEntity&gt;"/> class.
        /// </summary>
        /// <param name="startPos">The start position.  Used to set the starting value of the identity field</param>
        /// <remarks></remarks>
         public CounterObjectMap(Int32 startNum)
         {
             // Use the ID field as the primary key.
             Id(x => x.ID);
            Map(x => x.Counter).CustomSqlType("int IDENTITY(" + Convert.ToString(startPos) + ",1)").Not.Nullable().ReadOnly().Generated.Insert(); 
         }
         public CounterObjectMap()
         {
 
         }
    }
}

Implementing a Counter

This class is where the magic happens.  First we have a generic class that implements the Fluent ClassMap.  We have two constructors.  The first takes a single Int32 which we’ll use to setup the starting seed for the identity.  You could also add another parameter to this constructor that sets the increment by too if you’d like.  NHibernate needs an empty constructor so we add that here.  We setup the key as the guid and then setup a CustomSqlType to define an identity field using our starting number.  Next lets use this:

namespace Domain.TestCounter
{
    /// <summary>
    /// Domain object for the test counter- all properties are inherited from <see cref="CounterObject"/>.
    /// </summary>
    /// <remarks>Pretty simple class :)</remarks>
    public class TestCounter : CounterObject
    {
         
    }
 
    /// <summary>
    /// nHibernate mappings for <see cref="TestCounter"/>
    /// </summary>
    /// <remarks></remarks>
    public class TestCounterMap: CounterObjectMap<TestCounter>
    {
        /// <summary>
        /// Initializes a new instance of the mapping class.
        /// </summary>
        /// <remarks>Initialize the identity field for this table at 50K</remarks>
        public TestCounter(): base(50000)
        {
            Table("CounterTableName");
        }
    }
}

Pretty simple implementation for the domain object.  Just implement the base class.  The mapping is also pretty simple.  The key thing is to call the constructor from base CounterObjectMap with the starting number for the identity field.  Voila!

You could create a generic create call too if you felt so inclined – but in a nutshell if you persist/retrieve one of these objects your new SQL server generated counter will be in the TestCounter.Counter value.  Enjoy!

Technorati Tags: ,

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress

Switch to our mobile site