Tuesday, September 7, 2010

Enumerations Between Code and Database

One of my biggest pet peeves concerning enumerated types is how the values are serialized such as to a database field.  I absolutely detest storing numerical data in my database when the whole point of an enumeration is to make numerical data human readable.

For example, let's consider we have a database table for Orders and in that table we might have an OrderStatus field.  Let us also suppose that the following list represents all the status values that this field may have: (New, Processing, Denied,Approved,Completed).

In our C# code we have an enum defined like so...

enum OrderStatus { 
    New, 
    Processing, 
    Denied, 
    Approved 
};


Now, the easiest way to store this in the database would be to cast the enum to an int and  use ToString() in our code on our enum type which would produce a number (i.e. New = 1, Processing = 2, etc...).  But anyone trying to run a query on the database would have no idea that 1 meant New and 2 meant Processing, etc...  They would have to either open the source code and find out for themselves or ask a developer familiar with the project.

Order.Status = ((int)status).ToString();

The other option is to call ToString() directly on the enum value which will produce a string with the enum value equal to the name of the value.  

Order.Status = status.ToString();

The problem comes when you have to convert that string back into the enum type.  Of course you can do this inline with code such as the following...

enum status;
try {
    status = (OrderStatus)Enum.Parse(typeof(OrderStatus), databaseValue);
}
catch {
    status = OrderStatus.New; // default value
}

switch(status){
  case OrderStatus.New:
      ....
      break;
  ....
}
 
That sure is a lot of code just convert a string to an enum.  Of course, you could create a utility method to do the conversion, but then you would have to have a method for each enum type.  That seems like a waste of code also.  So the question is how can we contain this conversion into a single method that can be re-used for any enum type?

The answer lies in world of Generics.  Coupled with the new language feature of Extension Methods, and we have a simple, yet powerful solution.  I believe the code below pretty much explains it all...

public static class StringExtensions {

    public static T ToEnum<T>(this string s, T defaultValue) {
        try {
            return (T)Enum.Parse(typeof(T), s);
        }
        catch {
            return defaultValue;
        }
    }

}


And now our switch statement from the first section of code above is drastically simplified...
switch(databaseValue.ToEnum<OrderStatus>(OrderStatus.New)){
  case OrderStatus.New:
      ....
      break;
  ....
}


As you can see, any string can be parsed into any enumerated type with the same simple extension method.