CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeffrey Palermo [MVP]

Software management consultant and CTO, Headspring Systems

Using enum strings with NHibernate persistence - level 400

One of the things that is not very obvious when using NHibernate is how to using Enumerations.  If you merely map an enum with the hbm.xml, NHibernate will persist that class member as an int, which is the underlying type of an Enum value type.  Even if you have your database table configured with a string field, you'll get an integer in your string field.

To have NHibernate use the string representation of the enum for storing in the database, you need to use a special type class.  Below is a simple example of using the EnumStringType that NHibernate provides.  Consider the following enum that I want to use in my class (this is a very simplified example):

    public enum DeliveryStatus
    {
        Pending,
        Ready,
        Sent
    }


When mapping this in my class, NHibernate would persist 0, 1, and 2 in my database.  What I actually want are the strings to be stored in my table (no comments about normalization, please).  Here is a wierd thing you have to do to achieve this goal.  Here is my mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
    <class name="Palermo.Shipping.Shipment, Palermo.Shipping" table="Shipment">
        <id name="TrackingId" column="TrackingId" type="String" length="30" >
            <generator class="assigned"/>
        </id>
       
        <property name="DeliveryState" column="DeliveryState"
            type="Palermo.Shipping.DeliveryStatusType, Palermo.Shipping"/>
       
    </class>

</hibernate-mapping>


Notice that I have a new type referenced for DeliveryState:  DeliveryStatusType.  This is what's new.  This type helps NHibernate map an enum string instead of the int.  For this, I must define this type in my code:

    public class DeliveryStatusType : EnumStringType
    {
        public DeliveryStatusType() : base(typeof (DeliveryStatus), 30)
        {
        }
    }


Note that this is very simple, and the 30 specifies the max length of the enum string.  I'd recommend setting this number the same as the length of your string field in your database.

With these small steps, NHibernate will now map Pending, Ready, and Sent to the database field.  Normal programmatic interaction is the same.  NHibernate will take care of all the data access.  Without the above solution, one might be tempted to use string constants, but I'd highly recommend using enums when the possible values are known. 


Comments

Udi Dahan - The Software Simplist said:

For the performance concious, I would recommend staying with NHibernate's default behavior. That way you could probably have the column be smaller - like tinyint (how many enum values do you really have?) allowing more rows to be kept on the same page.

Moreover, since you would probably like to be able to perform queries like Get me all rows with Enum value X, indexes on int based columns take much less memory than string based indexes. And the performance of an int based index is also better than that of a string based index.

If you really want to have those strings in the database, create a lookup table, and join to it.
# March 16, 2006 2:04 AM

Jeffrey Palermo said:

You are correct. It takes more space in the database, but if you have the space to spare, it's easier to deal with. Your point is very valid, though.
# March 17, 2006 5:13 PM

Jeffrey Palermo said:

I received this directly from Dan Morphis via email:

While trying to solve another issue today I saw your blog posting on enum strings and NHibernate (http://codebetter.com/blogs/jeffrey.palermo/archive/2006/03/14/140949.aspx). Your solution was to use a one off C# Enum Mapper class.  After we had written out 5th or 6th one today, we decided there had to be a better way.  We ended up coming up with a generic enum mapper that works amazingly well.  My co-worker wrote all this up in his blog
(http://orand.blogspot.com/2006/12/generic-nhibernate-enum-string-mapping.html), and in-fact even referenced your blog posting.

# December 20, 2006 7:19 AM

About Jeffrey Palermo

Jeffrey Palermo is a software management consultant and the CTO of Headspring Systems in Austin, TX. Jeffrey specializes in Agile coaching and helps companies double the productivity of software teams. Jeffrey is an MCSD.Net , Microsoft MVP, Certified Scrummaster, Austin .Net User Group leader, AgileAustin board member, INETA speaker, INETA Membership Mentor, Christian, husband, father, motorcyclist, Eagle Scout, U.S. Army Veteran, and Texas A&M University graduate. Check out Devlicio.us!

This Blog

Syndication