Как сохранить перечисление в базе данных как строку

Это мой модельный класс, где у нас есть Тип, который может быть зомби или человеком

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

Я хочу сохранить данные как Human и Zombie, а не с int

Ответ 1

У меня была эта проблема, насколько я помню, и, честно говоря, я не знаю, почему MS не добавила эту функцию (NH может делать это так, как всегда).

Любые способы, что я обычно делал, это использовать классы константных строк, например:

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

}

Но поскольку у вас есть неявное преобразование, объявления классов являются единственными, кто должен знать о вспомогательных типах.

Ответ 2

Вы можете сохранить перечисление в 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/

Ответ 3

Не рекомендуется хранить их как строку, но вы можете создавать таблицы поиска для своих перечислений с помощью ef enum для поиска, и это очень просто использовать.

Ответ 4

Я считаю, что гораздо удобнее хранить их как int потому что вы можете легко enum int из базы данных в enum.

Но если это то, чего вы желаете, есть два подхода. Вы можете сохранить Type.Zombie.ToString() (или Type.Human.ToString() соответственно) в базу данных (которая будет "Zombie"), или вы можете получить значение DescriptionAttribute, которое вы используете, и сохранить его DB. Как получить описание описано здесь. - В этом случае это также будет "Зомби", но это может быть все, что вы пишете в Description().

Если вы используете ToString вы можете использовать Enum.Parse чтобы вернуть экземпляр enum. Если вы используете описание, это не так просто.