如何转换/存储多个ENUM选项?

时间:2012-12-30 17:01:50

标签: asp.net-mvc-3 nhibernate

我可以使用以下代码将enum转换为string。但是,它只存储一个选定的值。在选择TWO值的情况下,当我使用NHibernate存储它时会被截断。

这是我的代码:

MyEnum { One, Two, Three, Four, Five }

private static readonly string[] myEnum =
    Enum.GetNames(typeof(MyEnum));
public string MyProperty
{
    get {
        var value = new MyEnum();
        int i = (int)value;
        return i >= 0 && i < myEnum.Length ?
            myEnum[i] : i.ToString(); }
    set { 
        Record.MyProperty= value == 
            null ? null : String.Join(",", value); }
}

Record只是public virtual string MyProperty { get; set; }

任何人都可以提供我将如何存储的示例,例如以逗号分隔的形式,选择多个enum(例如,“一,二,五”由用户选择并且所有三个存储在DB)?

更新

我试图在get{}

中执行此操作
foreach (int i in Enum.GetValues(typeof(MyEnum)))
{
    return i >= 0 && i < myEnum.Length ? myEnum[i] : i.ToString();
}

但收到not all code paths return a value错误。

问题更新:

如果我用两个string执行此操作:

part.MyProperty = record.MyProperty;

使用@Jamie Ide下面的IEnumerable<MyEnum>回答无效,因为我无法将string转换为MyEnum

我如何编写最后一部分,以便在下面的答案中从@Jamie Ide获取IEnumerable<MyEnum>代码?

2 个答案:

答案 0 :(得分:3)

正如我的评论中所提到的,除非绝对要求将枚举存储为字符串,否则我建议使用[Flags]属性设置枚举并创建将枚举存储为int的约定。这是我使用的(注意我正在使用FluentNH):

惯例

public class EnumConvention : IUserTypeConvention
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        // You can use this if you don't want to support nullable enums
        // criteria.Expect(x => x.Property.PropertyType.IsEnum);

        criteria.Expect(x => x.Property.PropertyType.IsEnum ||
            (x.Property.PropertyType.IsGenericType &&
             x.Property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) &&
             x.Property.PropertyType.GetGenericArguments()[0].IsEnum)
            );
    }

    public void Apply(IPropertyInstance target)
    {
        target.CustomType(target.Property.PropertyType);
    }
}

枚举
请注意,为了保持按位比较的正常运行,您必须小心设置值。

// Note I use long to support enough enum values
[Flags]
public enum MyEnum : long
{
    Foo = 1,
    Bar = 1 << 1,
    Baz = 1 << 2
}

我相信你不应该做任何事情。无需迭代设置或检索,无需任何操作。要测试是否存在值,可以在枚举上使用HasFlag()扩展方法。

更新

要修改MvcGrabBag代码以支持此类枚举,您需要更改GetItemsFromEnum方法,如下所示:

public static IEnumerable<SelectListItem> GetItemsFromEnum<T>(T enumeration = default(T)) where T : struct
{
    FieldInfo[] fields = enumeration.GetType().GetFields(BindingFlags.Public | BindingFlags.Static);

    return from field in fields
                let value = Enum.Parse(enumeration.GetType(), field.Name)
                let descriptionAttributes = field.GetCustomAttributes(typeof(DescriptionAttribute), true)
                select new SelectListItem
                {
                    Text = descriptionAttributes.Length > 0
                                ? ((DescriptionAttribute)descriptionAttributes[0]).Description
                                : field.Name,
                    Value = Convert.ToInt64(value).ToString(),
                    Selected = (Convert.ToInt64(enumeration) & Convert.ToInt64(value)) == Convert.ToInt64(value)
                };
}

请注意,我仅将其保留为通用,因为我不知道该工具包的其他方面取决于该签名。但是,您可以看到没有必要删除<T>并拥有public static IEnumerable<SelectListItem> GetItemsFromEnum(Enum enumeration)这样的签名,它会正常工作。

另请注意,此代码使用的是支持从Description属性派生的名称的约定。我用它来让我的标签更具人性化。枚举看起来像这样:

[Flags]
public enum MyEnum : long
{
    [Description("Super duper foo")]
    Foo = 1,
    [Description("Super duper bar")]
    Bar = 1 << 1,
    // With no description attribute it will use the ToString value
    Baz = 1 << 2
}

答案 1 :(得分:1)

这是一个快速而肮脏的解决方案。在此解决方案中,_myEnumString将映射为私有字段并存储在数据库中。正如评论中所提到的,可以使用另一个表将数组存储为集合,如this question的答案所示,或者在this question中的一个表中。

    public enum MyEnum { One, Two, Three, Four, Five }

public class MyClass
{
    private string _myEnumString;

    public IEnumerable<MyEnum> MyEnums
    {
        get 
        { 
            return Array.ConvertAll(_myEnumString.Split(','), s => (MyEnum)Enum.Parse(typeof(MyEnum), s));
        }
        set
        {
            _myEnumString = string.Join(",", value.Select(v => v.ToString()));
        }
    }

}

更新

假设record.MyProperty和part.MyProperty都是MyEnum名称的分隔字符串(例如“One,Two,Three”),那么您可以映射MyProperty并创建一个只读属性以返回MyEnum的集合。

public class MyClass
{
    public string MyProperty { get; set; }

    public IEnumerable<MyEnum> MyEnums
    {
        get 
        { 
            return Array.ConvertAll(MyProperty.Split(','), s => (MyEnum)Enum.Parse(typeof(MyEnum), s));
        }
    }

}