0

I have a database which is accessed by multiple systems. Ours reads a table using Fluent Nhibernate and Automapping.

One of the columns is a string representing an enum. In most installations this is fine, but every now and then another system will persist an invalid value. How can I catch these invalid values and either convert or ignore them?

Example:

Database Table:
ID  MyEnum
0   "One"
1   "Two"
2   "Invalid"

MyEnum
{
  One,
  Two
}

I'm already using IAutoMappingOverride with my model, is there anyway to pass a function to the mapper to do validation/conversion (say I wanted to convert any unknowns to MyEnum.One)? Or is there a simpler way that I'm missing?

Where I got to was using a combination of @Firo's answer and the answers here and here

class SafeEnumType<T> : ImmutableUserType where T : struct
{
    public override object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        T value;
        if (Enum.TryParse((string)rs[names[0]], out value))
            return value;
        else
            return default(T);
    }

    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        NHibernateUtil.String.NullSafeSet(cmd, value.ToString(), index);
    }

    public override Type ReturnedType
    {
        get { return typeof(T); }
    }

    public override SqlType[] SqlTypes
    {
        get { return new[] { SqlTypeFactory.GetString(100) }; }
    }
}

and adding

mapping.Map(x => x.Type).CustomType(typeof(SafeEnumType<EventType>));

to my AutomapOverride.Override() fn

Community
  • 1
  • 1
Byron Ross
  • 1,595
  • 1
  • 14
  • 21

1 Answers1

1

In NHibernate there is IUserType which lets you define custom conversion code. here is a base class of mine which you can use because enums are immutable types

code

class SpecialEnumUserType : ImmutableUserType
{
    public override object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        TheSpecialEnum value;
        if (Enum.TryParse<TheSpecialEnum>((string)rs[names[0]], out value))
            return value;
        else
            return default(TheSpecialEnum);
    }

    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        NHibernateUtil.String.NullSafeSet(cmd, value.ToString(), index);
    }

    public override Type ReturnedType
    {
        get { return typeof(TheSpecialEnum); }
    }

    public override SqlType[] SqlTypes
    {
        get { return new[] { SqlTypeFactory.GetString(50) }; }
    }
}

and convention to apply them to every enum property

class EnumHandlingConvention : IPropertyConvention
{
    public void Apply(IPropertyInstance instance)
    {
        if (instance.Type == typeof(TheSpecialEnum))
        {
            instance.CustomType<SpecialEnumUserType>();
        }
    }
}
Community
  • 1
  • 1
Firo
  • 30,626
  • 4
  • 55
  • 94