Tag: ORM
Mapping Enums to custom strings in NHibernate
by Warlock on Jul.02, 2009, under .NET, Database
Many times when working with a legacy relation model and a newly developed C# object model that sits on top of the relational model, you may need to map enum values to/from arbitrary strings in the database using NHibernate.
For example, suppose you have a a work order object that three possible states: request, approved, denied. To represent this, you might use the following enum:
enum WorkRequestState
{
Request,
Approved,
Denied
};
But let’s assume that the legacy relational model has represented these values as strings: REQ, APR, DEN. You can’t change the values for the relational model, and you certainly don’t want to use these values in your enum because they are not as readable as the values shown above.
By default, NHibernate will automatically convert you enum to a string value that matches the name of the enum values if the table field a string, or it will convert to the integer value for the enum options if the table field is an integer.
To do the above custom mapping we must implement a custom NHibernate type.
First, create a new class that inherits NHibernate.Type.EnumStringType. In your constructor, pass the type of the enum you are handling, and the maximum number of characters that the enum values will be to the base class constructor:
class WorkRequestStateEnumStringType : NHibernate.Type.EnumStringType
{
public WorkRequestStateEnumStringType()
: base( typeof(WorkRequestState), 3)
{
}
...
}
Next, override the GetValue(...) method to map the enum value to the equivalent string.
public override object GetValue(object enm)
{
if( null == enm )
return String.Empty;
switch( (WorkRequestState)enm )
{
case WorkRequestState.Request : return "REQ";
case WorkRequestState.Approved : return "APR";
case WorkRequestState.Denied : return "DEN";
default : throw new ArgumentException("Invalid WorkRequestState.");
}
}
Override the GetInstance(...) method to map a string value to the equivalent enum value:
public override object GetInstance(object code)
{
code = code.ToUpper();
if( "REQ".Equals(code) )
return WorkRequestState.Request;
else if( "APR".Equals(code) )
return WorkRequestState.Approved;
else if( "DEN".Equals(code) )
return WorkRequestState.Denied;
throw new ArgumentException(
"Cannot convert code '" + code + "' to WorkRequestState.");
}
Finally, in the NHibernate mapping file, specify the property’s type as the derived EnumStringType class.
<class name="WorkRequest" table="work_request_table">
<property
name="Status"
column="status_field"
type="my.namespace. WorkRequestStateEnumStringType, MyAssembly" />
...
<class>
Note that when specifying this type, you must use the assembly-qualified name because the NHibernate code doing the mapping is in a separate assembly from the type you created.
This information has been derived from Jeremy Miller’s original post here.