web-dev-qa-db-fra.com

Comment enregistrer l'énumération dans la base de données sous forme de chaîne

Ceci est ma classe modèle où nous avons un type qui pourrait être un zombie ou un humain

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
}

Actuellement, il enregistre des données dans Int

enter image description here

Je veux enregistrer les données en tant qu'humain et zombie, pas avec int

22
ZCoder

J'ai eu ce problème pour autant que je m'en souvienne et honnêtement, je ne sais pas pourquoi MS n'a pas ajouté cette fonctionnalité (NH peut le faire comme toujours depuis ..).

Quoi qu'il en soit, ce que j'ai l'habitude de faire, c'est d'utiliser des classes de chaînes const comme:

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

}

Inconvénients - aussi simple que possible.

Inconvénients - vous perdez la vérification de type (bien qu'elle puisse être appliquée par programme).


Cette fois, j'ai essayé de penser à quelque chose de plus ambitieux. J'ai donc pris le concept décrit par Brian (qui présente certains inconvénients lorsque, par exemple, une énumération donnée est largement utilisée dans le domaine). Et bien .. j'ai obtenu le travail suivant:

Une classe de composants de base pour stocker les valeurs:

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

... ce qui serait fondamentalement suffisant ... sauf que EF ne prend pas en charge les types génériques ...

Cela signifie que pour chaque énumération, vous devez avoir quelque chose comme ...

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

Ce qui vous donne une plaque de chaudière qui pourrait être facilement générée, par exemple en utilisant des modèles T4.

Ce qui vous conduit finalement à utiliser:

public class CalendarEntry : Entity
{

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

}

Mais puisque vous avez une conversion implicite en place, les déclarations de classe sont les seules à connaître les types d'assistance.

7
Pawel Gorczynski

Vous pouvez enregistrer l'énumération dans la base de données sous forme de chaîne, et je suis d'accord avec dotctor que ce n'est pas la meilleure idée, mais si vous en avez besoin, vous devez apporter quelques modifications.

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

Ajoutez cette classe d'extension à votre projet.

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

Tous les détails sont ici - http://NoDogmaBlog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/

23
Bryan

Ce n'est pas une bonne idée de les stocker sous forme de chaîne, mais vous pouvez créer des tables de recherche pour vos énumérations avec ef enum to lookup et c'est très facile à utiliser.

4
Hamid Pourjam

Je pense qu'il est beaucoup plus utile de les stocker en tant que int car vous pouvez ensuite convertir le int de la base de données très facilement vers le enum.

Mais si c'est ce que vous désirez, il y a deux approches. Vous pouvez enregistrer Type.Zombie.ToString() (ou Type.Human.ToString() respectivement) dans la base de données (qui sera "Zombie"), ou vous pouvez obtenir la valeur de DescriptionAttribute, que vous utilisez et enregistrez-le dans la base de données. Comment obtenir la description est décrit ici . - Ce sera aussi "Zombie" dans ce cas, mais ce peut être tout ce que vous écrivez dans la Description().

Si vous utilisez ToString, vous pouvez alors utiliser Enum.Parse pour récupérer l'instance de enum. Si vous utilisez la description, ce n'est pas si simple.

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