2015-09-12 18 views
11

Questa è la mia classe Modello dove abbiamo un tipo che potrebbe essere uno zombie o umanoCome risparmiare enum nel database come stringa

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 
} 

Attualmente è il salvataggio dei dati in Int

enter image description here

Voglio salvare i dati come Umano e Zombi, non con int

+1

Un'enumerazione è un oggetto statico, non è necessario salvarlo nel database ... In realtà è necessario definire gli elementi nel database e quindi generare l'enum nel codice utilizzando un modello T4. –

+4

Un valore enum _is_ un int. Dovresti davvero salvarlo così. A meno che tu non abbia una buona ragione per averla come una stringa nel DB .. Che suppongo tu non lo faccia. –

+3

@ Pierre-LucPineault: non è pericoloso memorizzarlo come un int? Non tutti gli utenti devono riordinare l'enumerazione e quindi immediatamente tutti i valori nel database puntano all'enumerazione errata senza alcun avviso – Diskdrive

risposta

3

Ho avuto questo problema per quanto mi ricordo e onestamente non so il motivo per cui non ha MS aggiungere questa funzione (NH può fare come da sempre. .).

Eventuali modi, quello che di solito fatto è utilizzare classi di stringhe const come:

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

} 

Contro - semplice come può essere.

Aspetti negativi: si perde il controllo del tipo (anche se potrebbe essere applicato a livello di codice).


Quindi questa volta ho cercato di pensare a qualcosa di più ambizioso. Così ho preso il concetto descritto da Brian (che ha alcuni aspetti negativi quando ad esempio un dato enum è ampiamente utilizzato nel dominio). E bene .. Ho ottenuto il seguente lavoro:

Una base di classe componente per memorizzare i valori:

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

... che sarebbe sostanzialmente sufficiente .. tranne EF non supporta i tipi generici .. .

Ciò significa che per ogni enum devi avere qualcosa di simile ...

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

che ti dà un po 'di caldaia-piastra che potrebbero essere facilmente generato per esempio usando i modelli T4.

che alla fine si finisce con l'utilizzo di:

public class CalendarEntry : Entity 
{ 

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

} 

Ma dal momento che si dispone di conversione implicita in atto, dichiarazioni di classe sono gli unici ad essere a conoscenza dei tipi di supporto.

+0

Dove si trova questo metodo string.ToEnum (); - è un metodo di estensione – Ken

+0

@Ken sì - 'public static T ToEnum (questo valore stringa) { ritorno (T) Enum.Parse (typeof (T), il valore, true); } ' –

3

Non è una buona idea archiviarli come stringa ma è possibile creare tabelle di ricerca per la propria en ums con ef enum to lookup ed è molto facile da usare.

+2

Felice che ti piaccia :-) Vedi anche http://stackoverflow.com/q/11167665/10245 –

+0

Puoi spiegare un po 'perché non è una buona idea memorizzare enum come 'nvarchar()'? Il testo non è più leggibile di un intero nel database? – Blaise

+0

Flessibilità e prestazioni @ Blaise – dotctor

1

Io, che è molto più utile archiviarli come int perché è possibile trasmettere lo int dal DB molto facilmente allo enum.

Ma se ciò che desideri, ci sono due approcci. È possibile salvare Type.Zombie.ToString() (o Type.Human.ToString() rispettivamente) nel database (che sarà "Zombie"), oppure è possibile ottenere il valore di DescriptionAttribute, che si sta utilizzando e salvarlo nel DB. Come ottenere la descrizione è descritto here. - In questo caso, sarà anche "Zombi", ma potrebbe essere qualsiasi altra cosa che scrivi nello Description().

Se si utilizza ToString, è possibile utilizzare Enum.Parse per recuperare l'istanza dello enum. Se usi la descrizione, non è così facile.

+1

Entity Framework ora supporta enumerazioni e non è necessario eseguire il cast di int dal DB al rispettivo valore enum. – dotctor

9

È possibile salvare l'enum sul db come stringa e sono d'accordo con dotctor che non è l'idea migliore, ma se è necessario, è necessario apportare alcune modifiche.

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

Aggiungi questa classe di estensione al tuo progetto.

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

Tutti i dettagli sono qui - http://NoDogmaBlog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/

+1

come utilizzerei questo per tracciare sia l'etichetta che l'id nel database? Sto ottenendo un'eccezione ad argomenti nulli quando prendo un record. – TWilly

+1

Provare a rimuovere [NotMapped] e impostarlo su un'altra colonna nel db – Bryan

+1

l'unica risposta effettiva alla domanda dell'OP. :) – toddmo

Problemi correlati