2015-09-12 15 views
11

Enum in der Datenbank speichern Dies ist meine Model-Klasse, wo wir einen Typ haben, dieWie als String

enter image description here

wird zum Speichern von Daten in Int

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 
} 

Derzeit wird ein Zombie oder ein Mensch sein könnte

Ich möchte die Daten als Mensch und Zombie speichern, nicht mit int

+1

Eine Enumeration ist ein statisches Objekt, es hat keinen Sinn, es in der Datenbank zu speichern ... Eigentlich sollten Sie die Elemente in der Datenbank definieren und dann Ihre enum im Code mit einer T4-Vorlage generieren. –

+4

Ein Enum-Wert _ist_ ein int. Sie sollten es wirklich so speichern. Es sei denn, Sie haben einen sehr guten Grund, um es als eine Zeichenfolge in der Datenbank zu haben. Was Sie nicht tun. –

+3

@ Pierre-LucPineault: ist es nicht gefährlich, es als int zu speichern? Würde nicht alles jemand tun, ist die Reihenfolge neu ordnen und dann sofort alle Werte in Ihrer Datenbank zeigt auf die falsche Enum ohne Warnung – Diskdrive

Antwort

3

Ich hatte dieses Problem so weit ich mich erinnern und ehrlich ich weiß nicht, warum MS nicht diese Funktion hinzufügen (NH kann es wie da immer tun. .).

Alle Möglichkeiten, was ich const strings Klassen Normalerweise ist das nicht genutzt haben, wie:

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

} 

Nachteile - so einfach kann sein.

Nachteile - Sie verlieren Typprüfung (obwohl es programmgesteuert erzwungen werden könnte).


Also dieses Mal habe ich versucht, etwas Ehrgeizigeres zu denken. Also nahm ich das von Brian beschriebene Konzept (das einige Nachteile hat, wenn beispielsweise ein gegebenes Enum in der Domäne weit verbreitet ist). Und gut .. Ich habe die folgenden Arbeiten:

Eine Basiskomponentenklasse, die Werte zu speichern:

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

... die .. grundsätzlich ausreichen würde, außer EF nicht generische Typen unterstützen .. .

Das bedeutet für jeden Enum Sie so etwas wie ...

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

haben, die Ihnen einig Kessel-Platte gibt, die leicht zum Beispiel erzeugt werden könnten Verwenden von T4-Vorlagen.

Welche Sie schließlich mit der Verwendung endet:

public class CalendarEntry : Entity 
{ 

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

} 

Aber da Sie implizite Konvertierung an der richtigen Stelle, Klassendeklarationen sind die einzigen, die sich der Helfer Typen.

+0

Wo ist diese Methode gefunden string.ToEnum (); - ist es eine Erweiterung Methode – Ken

+0

@Ken ja - 'public static T ToEnum (dieser Zeichenfolge-Wert) { return (T) Enum.Parse (typeof (T), den Wert, true); } ' –

3

Es ist keine gute Idee, sie als String zu speichern, aber Sie können Look-Up-Tabellen für Ihre en erstellen ums mit ef enum to lookup und es ist sehr einfach zu bedienen.

+2

Froh, dass Sie es mögen :-) Siehe auch http://Stackoverflow.com/q/11167665/10245 –

+0

Können Sie bitte ein wenig erklären, warum es keine gute Idee ist, enum als 'nvarchar()' zu speichern? Ist Text nicht lesbarer als eine Ganzzahl in der Datenbank? – Blaise

+0

Flexibilität und Leistung @Blaise – dotctor

1

I Sache, dass es viel nützlicher ist, sie als int zu speichern, weil Sie dann die int von DB sehr leicht auf die enum werfen können.

Aber wenn es, was Sie wünschen, gibt es zwei Ansätze. Sie können Type.Zombie.ToString() (bzw. Type.Human.ToString()) in der Datenbank speichern (die "Zombie" ist), oder Sie können den Wert DescriptionAttribute, den Sie verwenden, erhalten und diesen in der DB speichern. Wie man die Beschreibung bekommt, ist here beschrieben. - In diesem Fall wird es auch "Zombie" sein, aber es könnte sein, was auch immer du in der Description() schreibst. Wenn Sie ToString verwenden, können Sie Enum.Parse verwenden, um die Instanz des enum zurück zu erhalten. Wenn Sie die Beschreibung verwenden, ist es nicht so einfach.

+1

Entity Framework unterstützt nun enums und es ist nicht notwendig, den int von DB auf den entsprechenden Wert zu setzen. – dotctor

9

Sie können die Enumeration als String in der Datenbank speichern, und ich stimme Dotctor zu, dass es nicht die beste Idee ist, aber wenn Sie müssen, müssen Sie ein paar Änderungen vornehmen.

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

Fügen Sie diese Erweiterungsklasse Ihrem Projekt hinzu.

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

Alle Details sind hier - http://NoDogmaBlog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/

+1

Wie würde ich dies verwenden, um sowohl das Label als auch die ID in der Datenbank zu verfolgen? Ich erhalte eine Null-Argument-Ausnahme, wenn ich einen Datensatz abrufe. – TWilly

+1

Versuchen Sie, [NotMapped] zu entfernen und setzen Sie es auf eine andere Spalte in der db – Bryan

+1

die einzige tatsächliche Antwort auf die OP-Frage. :) – toddmo