web-dev-qa-db-ja.com

データベースに列挙を文字列として保存する方法

これは私のモデルクラスで、ゾンビまたは人間のタイプがあります

public class User
{
    public int ID { get; set; }
    public string Name { get; set; }
    public Type Type { get; set; }
    public List<Wepon> WeposInList { get; set; }
    }  

public enum Type
{   [Description("Zombie")] Zombie,
    [Description("Human")] Human
}

現在、Intにデータを保存しています

enter image description here

データをintではなくHumanとZombieとして保存したい

22
ZCoder

私は覚えている限りこの問題を抱えていましたが、正直なところ、なぜこの機能をMSが追加しなかったのかわかりません(NHはいつでも好きなようにできます)。

いずれにしても、私が通常やったことは、次のようなconst文字列クラスを使用することです。

public static class MyEnum
{
    public const string Foo = "Foo";
    public const string Bar = "Bar";
}

public class Client
{

    public string MyVal { get; set; }

    public Client()
    {
        MyVal = MyEnum.Bar;
    }

}

短所-できるだけシンプル。

欠点-型チェックを緩めます(ただし、プログラムで強制できます)。


そこで今回は、もっと野心的なことを考えようとしました。だから私はブライアンによって説明された概念を取りました(例えば、特定の列挙型がドメイン全体で広く使用されている場合、いくつかの欠点があります)。そしてまあ..私は次の仕事を得た:

値を保存する基本コンポーネントクラス:

[ComplexType]
public class DbEnum<TEnum>
{
    public string _ { get; set; }

    public DbEnum()
    {
        _ = default(TEnum).ToString();
    }

    protected DbEnum(TEnum value)
    {
        _ = value.ToString();
    }

    public TEnum ToEnum()
    {
        return _.ToEnum<TEnum>();
    }

    public static implicit operator DbEnum<TEnum>(TEnum value)
    {
        return new DbEnum<TEnum>(value);
    }

    public static implicit operator TEnum(DbEnum<TEnum> value)
    {
        return value.ToEnum();
    }
}

...これは基本的に十分です。EFがジェネリック型をサポートしていないことを除いて...

つまり、列挙型ごとに次のようなものが必要です...

public enum PrivacyLevel
{
    Public,
    Friends,
    Private
}

public class PrivacyLevelEnum : DbEnum<PrivacyLevel>
{
    public PrivacyLevelEnum() : this(default (PrivacyLevel))
    {      
    }

    public PrivacyLevelEnum(PrivacyLevel value) : base(value)
    {
    }

    public static implicit operator PrivacyLevelEnum(PrivacyLevel value)
    {
        return new PrivacyLevelEnum(value);
    }

    public static implicit operator PrivacyLevel(PrivacyLevelEnum value)
    {
        return value.ToEnum();
    }
}

これにより、簡単に生成できるボイラープレートが得られます。 T4テンプレートを使用します。

最終的に使用することになります:

public class CalendarEntry : Entity
{

    public virtual PrivacyLevelEnum PrivacyLevel { get; set; } = new PrivacyLevelEnum();

}

ただし、暗黙的な変換が行われているため、ヘルパー型を認識するのはクラス宣言のみです。

7

Enumを文字列としてdbに保存できます。これは最善のアイデアではないことをdotctorに同意しますが、必要な場合は、いくつかの変更を加える必要があります。

public class User
{
    public int ID { get; set; }
    public string Name { get; set; }
    public List<Wepon> WeposInList { get; set; }

    [Column("Type")]
    public string TypeString
    {
       get { return Type.ToString(); }
       private set { Type= value.ParseEnum<Type>(); }
    }

    [NotMapped]
    public Type Type { get; set; }
}  

この拡張クラスをプロジェクトに追加します。

public static class StringExtensions
{
    public static T ParseEnum<T>(this string value)
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }
}

詳細はこちら- http://NoDogmaBlog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/

23
Bryan

それらを文字列として保存することは良い考えではありませんが、 ef enum to lookup を使用して列挙型のルックアップテーブルを作成でき、非常に使いやすいです。

4
Hamid Pourjam

DBからintに非常に簡単にintをキャストできるので、enumとして保存する方がはるかに便利です。

しかし、それがあなたが望むものなら、2つのアプローチがあります。 Type.Zombie.ToString()(またはType.Human.ToString())をデータベース(「ゾンビ」)に保存するか、使用しているDescriptionAttributeの値を取得できます。それをDBに保存します。説明の取得方法は here で説明されています。 -この場合も「ゾンビ」になりますが、Description()に記述した他のものであれば何でもかまいません。

ToStringを使用する場合は、 Enum.Parseenumのインスタンスを取得します。説明を使用すると、それほど簡単ではありません。

1
Matyas
modelBuilder.Entity<DataSet>().Property(d => d.SemanticType).HasConversion(new EnumToStringConverter<DataSetSemanticType>());
0
Martin Staufcik