1

次のコードでenumをに変換することができます。stringただし、選択された値の1つのみが格納されます。2つの値が選択されている場合、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のを保存する方法のサンプルを提供できますか(たとえば、「1、2、5」がユーザーによって選択され、3つすべてが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エラーが発生しています。

質問の更新:

私がこれを2つで行った場合string

part.MyProperty = record.MyProperty;

@Jamie Ideからの以下の回答を使用IEnumerable<MyEnum>すると、に変換できないため機能stringしませんMyEnum

IEnumerable<MyEnum>以下の回答の@JamieIdeからコードを取得するために、その最後の部分をどのように記述すればよいでしょうか。

4

2 に答える 2

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
}
于 2013-01-02T15:33:42.647 に答える
1

これが迅速で汚い解決策です。このソリューションでは、_myEnumString はプライベート フィールドとしてマップされ、データベースに格納されます。コメントで述べたように、この質問への回答に示されているように別のテーブルを使用して、またはこの質問ように 1 つのテーブルに配列をコレクションとして格納することができます。

    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));
        }
    }

}
于 2012-12-31T14:35:39.207 に答える