Why enums are not a good replacement for lookup tables


Here is the issue, in a nutshell. You have a drop down you want to fill. You have two choices*:
  1. Put the options in a database table
  2. Put the options in an enum

* NOTE: I realize there are other choices, like hardcoding your drop down, etc., but I am trying to choose the saner options. Wink

Both are perfectly good options, in certain situations. In general, however, you want the option that has the easiest path for change. This is not the enum. Now, there are instances where the enum option is going to be easier. In those situations, you probably want to put the enum in a library separate from your working bits, especially if you have tightly coupled your objects to your back end. I am going on tangents now that I have already discussed. Click here for a bit about separation of concerns.

Here is the situation I am looking at. First, the enum:

public

enum Foo : int
{
    [Description(
"Bar Option 1"
)]
    Bar = 1,
    [Description(
"Bar Option 2"
)]
    Bar2 = 20
}

Nice use of attributes to add descriptions, right? And, you can code something like so to pull the descirptions for your DropDownList:

ddEvent.Items.Insert(0,
new ListItem(enum_support.GetDescription(Foo.Bar), Convert.ToString((int)Foo.Bar)));

ddEvent.Items.Insert(0,
new ListItem(enum_support.GetDescription(Foo.Bar2), Convert.ToString((int)Foo.Bar2)));

At this time, it seems we are rather clever. But the boss asks to update the drop down to say change "Bar Option 1" to read "Power Up" and "Bar Option 2" to read "Power Down". You are now recompiling libraries for a simple label change. Ouch!

There is another issue with storing these items in an enum in this fashion. When I want to produce a report, I have to invoke something like this to fill in the report.

lblEvent.Text = r.Event.ToString();

I can’t simply pull the data from the database. I could add a lookup table to match the enum, but I then risk having the table and the enum out of sync. To keep it in sync, I could either generate the enum on the fly (in memory only) or code generate the enum, but why should I have this extra step? It makes no sense.

There are good reasons to use enums. Enums are great, for example, when you have an input for a method that can only take a limited set of values. You use the enum to avoid having to check values on the int being passed in. But this type of enum is specific to the class or classes in the library. It is not a global enum.

I am a proponent of using a persistent store for metadata. I have nothing against an enum class coded inside some helper library, but if the enum is used globally it better be in a helper library rather than located in the first library that uses it. The word is REFACTOR. ALthough I am not against these types of enums, I still believe that most of your global enums should be lookup tables. And, if you are grabbing data with numerics that correspond to the enum, I would state it is mandatory that you create a lookup table rather than an enum. By mandatory, I do not mean the enum will not work, just that it is less flexible (extensible) and requires much more work to update (compile versus SQL change).

Peace and Grace,
Greg

Advertisements

3 Responses to Why enums are not a good replacement for lookup tables

  1. Alan says:

    I’m torn on this issue. In the Visual FoxPro world, we put all kinds of metadata in dbfs. These days, I don’t like putting anything outside the scope of my unit tests. I think the options in the list are the result of user stories, so should live in the application, not the db. Furthermore, putting the metadata in the DB puts it beyond the scope of thorough change management in general, not just unit tests.++Alan

  2. Dylan says:

    I agree–I generally use lookup tables as opposed to enums. They are easier to change, and you also get the added bonus of being able to store additional information about the choice, rather than just an ID and a name.However, I tend to also create enums for lookup tables that don’t change a lot (phases, statuses, etc.–things that would only change accompanying major rewriting/reconfiguring of an application), with the enum values matching the lookup table ID. This helps when making reference to important lookup fields that may actually be hardcoded in program logic–for example, the initial status of a record, or the first phase of a process, or something like that.

  3. Gregory says:

    I see where you are coming from Alan, but you can set up test data and use a pattern that allows you to inject that data. It does not violate your tests and your production data still pulls from a persistent store. In addition, unless you are testing the UI, you can mock any type of data into the test to see if the "correct data" is being pulled from the test, as you are testing the code, not the data. ANd, if you are testing UI, it is not normally an automated unit test, but some form of integration test where pulling from the database is a valid exercise.
     
    — Greg

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: