当枚举值与字符串值不匹配时,处理来自nHibernate EnumStringType的异常

时间:2013-12-20 00:58:03

标签: c# nhibernate

她是我的情况,其中枚举值在Db中以字符串形式存储。在检索时,我尝试使用具有基类为EnumStringType的mytype将字符串转换为枚举时遇到异常。

以下是我遇到的错误:

NHibernate.HibernateException : Can't Parse Enum4 as MyEnum

例如:来自数据库的值为:“Enum4”

根据MyEnum代码的有效枚举值为:

Enum1 Enum2 Enum3

在代码适应变化之前,以某种方式在Db中引入了Enum4。 (我知道发生了疯狂的事情)

异常是正常的,因为我的Enum没有来自数据库的这个值。但我不希望用户得到异常。而是默认为第一个值。 (我同意在某些情况下这不行,但它可以防止在我的情况下更严重的异常)

如果我是正确的,GetInstance是执行从字符串到枚举的转换的方法。是否有某种类型的TryGetXXXX可以解决这个问题或如何解决它?

谢谢你的时间!

以下是我正在使用的Enum代码来解决此问题:

public class EnumMappingBase : EnumStringType
{
    public EnumMappingBase(Type type)
        :base(type)
    { 

    }

    public override object GetInstance(object code)
    {
        return base.GetInstance(code); // Here is where I get the exception. 
        // I am thinking this is where capturing the exception and defaulting must happen. 
        // I wish I had a TryGetInstance() here or may be it is there and I am not aware.
    }

    public override object GetValue(object code)
    {
        return base.GetValue(code);
    }

}

public enum MyEnum
{
    Enum1,
    Enum2,
    Enum3
}

public class MyEnumType : EnumMappingBase
{
    public MyEnumType()
        : base(typeof(MyEnum))
    {

    }
}

2 个答案:

答案 0 :(得分:4)

尝试在MyEnumType中覆盖GetInstance(),如下所示:

public class MyEnumType : EnumMappingBase
{
    public MyEnumType()
        : base(typeof(MyEnum))
    {}

    public override object GetInstance(object code)
    {
        // Set the desired default value
        MyEnum instanceValue = MyEnum.Enum1;
        Enum.TryParse(code, true, out instanceValue);

        return instanceValue;    
    }
}

答案 1 :(得分:1)

我今天遇到了同样的问题,并且 kay.herzams 回答帮助创建了这个可以用于任何枚举类型的类。

它更通用,更灵活,所以我想我会为寻找通用解决方案的人分享它。

https://gist.github.com/flopes89/f6c4a079ee3b82c7a1df

using System;
using System.Reflection;
using log4net;
using NHibernate.Type;

/// <summary>
/// This class serves as a helper class to properly en- and decode enum values to/from strings
/// using hibernate. It is a generic class that can be used with any enumeration type and is designed
/// to replace the standard NHibernate.EnumStringType entirely.
/// 
/// This class should be used whenever an enumeration is consisted via NHibernate, because it has a failsafe
/// decoding of enumeration values from the database by defaulting them back to the given default value
/// when an unknown enumeration value is found in the database, which the default NHibernate.EnumStrinType does not
/// </summary>
/// <typeparam name="T">The enumeration type to use</typeparam>
public class EnumStringType<T> : EnumStringType where T : struct
{
    private static ILog _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
    private T _defaultValue;

    /// <summary>
    /// Create the type
    /// </summary>
    /// <param name="defaultValue_">Value to fallback to if an unknown enum value is found</param>
    public EnumStringType(T defaultValue_)
        : base(typeof(T))
    {
        _defaultValue = defaultValue_;
    }

    /// <summary>
    /// Get the value of the given code
    /// </summary>
    /// <param name="code_">The code will be decoded using Enum.TryParse with the Type of this EnumStringType instance</param>
    /// <returns>Either the defaultValue of this instance (logged with a warning) or the value of the code</returns>
    public override object GetInstance(object code_)
    {
        T instanceValue = _defaultValue;

        if (code_ != null && Enum.TryParse<T>(code_.ToString(), true, out instanceValue)) {
            _logger.Debug("Decoded [" + typeof(T) + "] enum value [" + instanceValue + "]");
        }
        else {
            _logger.Warn("Unknown [" + typeof(T) + "] enum value [" + code_ + "] found, defaulting to [" + instanceValue + "]");
        }

        return instanceValue;
    }
}

用法示例:

public enum Permission
{
    NULL,
    EDIT
}

public class PermissionStringType : EnumStringType<Permission>
{
    public PermissionStringType()
        : base(Permission.NULL)
    {

    }
}

映射可以通过以下方式完成:

<set name="Permissions" table="permissions" lazy="true">
    <key column="role"/>
    <element column="name" type="My.Namespace.PermissionEnumStringType,MyAssemblyName"/>
</set>