State Pattern, Enumeration Class and Fluent NHibernate (Oh my!)

Recently, I needed to change a basic enumeration into a full-fledged state pattern. After getting all my domain classes updated, I began reviewing the persistence layer. And I hit a wall. I wasn’t sure how I wanted to update my Fluent NHibernate convention to persist the current state.

My original classes were similar to this:

public class MyProgress{ 
   public virtual Guid Id { get; set; }
   ...
   ... 
   public virtual MyStatus Status { get; private set; }
}

public enum MyStatus{ 
   New, 
   InProgress, 
   Completed, 
   Canceled, 
   Failed
}

My new state pattern was similar to this:

public abstract class MyStatus
{
    public static readonly MyStatus New = new NewStatus();
    public static readonly MyStatus InProgress = new InProgressStatus();
    ...
}

public class NewStatus: MyStatus
{
    public override void Start(MyProgress progress)
    {
        progress.SetStatus(InProgress);
    }
    public override void Cancel(MyProgress progress)
    {
        progress.SetStatus(Cancelled);
    }
    public override void Fail(MyProgress progress)
    {
            progress.SetStatus(Failed);
    }
}
...

Here is the problem: My enumeration was persisted as an integer field on the record. Now that I had a state pattern, how should I save my state? I googled the problem and found Derick Bailey’s article on the state pattern and Fluent NHibernate. Derick’s pattern works well, but I felt that creating a lookup table in my database just so I can persist a value in another table was not the path I wanted to traverse – I wasn’t persisting an entity, I was persisting a state value on an entity. Not finding any more love from Google, I asked around and was advised to contact fellow Elegant Coder and Guild3 member, Jason Grundy. Here is Jason’s advice:

“I’ve recently changed from using Enums to an approach outlined by Jimmy Bogard here. In the Entity I would do something like this:

protected int _orderStatusId;
public virtual OrderStatus OrderStatus
{
    get { return Enumeration.FromValue<OrderStatus>(_orderStatusId); }
    set { _orderStatusId = value.Value; }
}

Then in Fluent NH you can simply map to the protected member.”

I decided to pursue Jason’s advice.  The result is my database tables did not need to change at all. Here is some snippets of the updated classes:

public class MyProgress
{
     public virtual Guid Id {get;set;}
     ...
     protected int _status;
     public virtual MyStatus
     {
         get{ return Enumeration.FromValue<MyStatus>(_status); }
         set{ _status = value.Value; }
     }
     ...
}
 
public class MyStatus : Enumeration
{
     public static MyStatus New = new NewStatus();
     ...
 
     private class NewStatus : MyStatus
    {
         public NewStatus() : base (0,"New"){}

         public override void Start(MyProgress progress)
         {
             progress.SetStatus(InProgress);
         }
    }
     ...

Notice that the MyStatus class is no longer abstract. However, the subclasses are all private nested classes, each with a value and a display name. I set each subclass value to match the enumeration value it replaced. I did not need to convert my existing data to a new schema.

And here is the Fluent NHibernate override:

public class MyProgressOverride : IAutoMappingOverride<MyProgress>
{
    public void Override(AutoMapping<MyProgress> mapping)   
    {
        mapping.Map(x => x.Status)
            .CustomType(typeof(int))
            .Access.CamelCaseField(Prefix.Underscore);
    }
}

As you can see, we use convention-based automapping with overrides, but this same map could be used in a standard class map.

Thanks to Jimmy, Derick, and Jason for the inspiration and assistance!

comments powered by Disqus