0

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

Posted by Richard Cirerol on Nov 1, 2009 in - Dotnet  | View Original Article
 

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!

Tags: ,

Copyright © 2010 Answer My Query All rights reserved. Maintained by Orange Brains .