Come creare una tabella corrispondente all’enum in EF6 Code First?

Ho seguito MSDN su come gestire le enumerazioni in Code First per EF6. Ha funzionato, come previsto, ma il campo nella tabella creata che fa riferimento all’enumeratore è un semplice int .

Preferirei che fosse prodotta una seconda tabella, i cui valori avrebbero seguito la definizione dell’enumeratore nel codice C #. Quindi, invece di ottenere solo una tabella corrispondente a Department nell’esempio su MSDN, mi piacerebbe anche vedere una seconda tabella popolata dagli elementi di Faculty .

public enum Faculty { Eng, Math, Eco } public partial class Department { [Key] public Guid ID { get; set; } [Required] public Faculty Name { get; set; } } 

Ricercando il problema, mi sono imbattuto in una soluzione , che suggerisce di creare una tabella per l’enumerazione e di popolarla esplicitamente tramite il seeding.

Mi sembra un approccio ingombrante e un sacco di lavoro che dovrebbe essere gestito automagicamente. Dopo tutto, il sistema sa quali valori effettivi costituiscono l’enumerazione. Dal punto di vista del DB, sono ancora file di dati, proprio come le quadro che creo ma dall’aspetto di OO, non è realmente un dato – piuttosto un tipo (liberamente express) che può assumere un numero di stati finiti e prima conosciuti.

È raccomandato l’approccio di popolamento della tabella “manualmente”?

Poiché EF non lo gestisce automaticamente, , questo è il metodo consigliato.

Suggerisco alcune modifiche all’articolo che hai fornito.

Rinomina il tuo enum

 public enum FacultyEnum { Eng, Math, Eco } 

Crea una class che rappresenti la tabella

 public class Faculty { private Faculty(FacultyEnum @enum) { Id = (int)@enum; Name = @enum.ToString(); Description = @enum.GetEnumDescription(); } protected Faculty() { } //For EF [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id { get; set; } [Required, MaxLength(100)] public string Name { get; set; } [MaxLength(100)] public string Description { get; set; } public static implicit operator Faculty(FacultyEnum @enum) => new Faculty(@enum); public static implicit operator FacultyEnum(Faculty faculty) => (FacultyEnum)faculty.Id; } 

Il tuo modello fa riferimento alla class

 public class ExampleClass { public virtual Faculty Faculty { get; set; } } 

Creare un metodo di estensione per ottenere la descrizione dai valori enum e seed

 using System; using System.ComponentModel; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Linq; public static class Extensions { public static string GetEnumDescription(this TEnum item) => item.GetType() .GetField(item.ToString()) .GetCustomAttributes(typeof(DescriptionAttribute), false) .Cast() .FirstOrDefault()?.Description ?? string.Empty; public static void SeedEnumValues(this IDbSet dbSet, Func converter) where T : class => Enum.GetValues(typeof(TEnum)) .Cast() .Select(value => converter((TEnum)value)) .ToList() .ForEach(instance => dbSet.AddOrUpdate(instance)); } 

Aggiungi il seme in Configuration.cs

 protected override void Seed(Temp.MyClass context) { context.Facultys.SeedEnumValues(@enum => @enum); context.SaveChanges(); } 

Aggiungi la tabella enum nel tuo DbContext

 public class MyClass : DbContext { public DbSet Examples { get; set; } public DbSet Facultys { get; set; } } 

Usalo

 var example = new ExampleClass(); example.Faculty = FacultyEnum.Eng; if (example.Faculty == FacultyEnum.Math) { //code } 

Ricordare

Se non si aggiunge virtual nella proprietà Faculty, è necessario utilizzare il metodo Include da DbSet per eseguire Eager Load

 var exampleFromDb = dbContext.Examples.Include(x => x.Faculty).SingleOrDefault(e => e.Id == 1); if (example.Faculty == FacultyEnum.Math) { //code } 

Se la proprietà Faculty è virtuale, basta usarla

 var exampleFromDb = dbContext.Examples.Find(1); if (example.Faculty == FacultyEnum.Math) { //code } 

In base alla risposta @ Alberto Monteiro, ho creato una class generica nel caso in cui si disponga di più tabelle. L’avviso qui è che Id è il tipo di TEnum. Usarlo in questo modo fornirà l’opzione per usare Enum per dichiarare il tipo di proprietà.

 public class Question { public QuestionTypeEnum QuestionTypeId { get; set; } // field property public QuestionType QuestionType { get; set; } // navigation property } 

Per impostazione predefinita, Enum utilizza numeri interi, quindi il provider db creerà un campo con il tipo “int”.

EnumTable.cs

  public class EnumTable where TEnum : struct { public TEnum Id { get; set; } public string Name { get; set; } protected EnumTable() { } public EnumTable(TEnum enumType) { ExceptionHelpers.ThrowIfNotEnum(); Id = enumType; Name = enumType.ToString(); } public static implicit operator EnumTable(TEnum enumType) => new EnumTable(enumType); public static implicit operator TEnum(EnumTable status) => status.Id; } 

ExceptionHelpers.cs

 static class ExceptionHelpers { public static void ThrowIfNotEnum() where TEnum : struct { if (!typeof(TEnum).IsEnum) { throw new Exception($"Invalid generic method argument of type {typeof(TEnum)}"); } } } 

Ora puoi ereditare l’EnumTable

 public enum QuestionTypeEnum { Closed = 0, Open = 1 } public class QuestionType : EnumTable { public QuestionType(QuestionTypeEnum enumType) : base(enumType) { } public QuestionType() : base() { } // should excplicitly define for EF! } 

Seme i valori

 context.QuestionTypes.SeedEnumValues(e => new QuestionType(e)); 

Un’altra possibilità, se vuoi mantenere il tuo modello più semplice come stile POCO, è usare l’enum con una proprietà che verrà memorizzata come un intero dal framework di entity framework.

Quindi, se si desidera che le “tabelle enum” vengano create e aggiornate nel DB, si consiglia di utilizzare il pacchetto nuget https://github.com/timabell/ef-enum-to-lookup e utilizzarlo in un seme di migrazione EF metodo per esempio:

 public enum Shape { Square, Round } public class Foo { public int Id { get; set; } public Shape Shape { get; set; } } public class MyDbContext : DbContext { public DbSet Foos { get; set; } } using(var context = new MyDbContext()) { var enumToLookup = new EnumToLookup { TableNamePrefix = string.Empty, NameFieldLength = 50, UseTransaction = true }; enumToLookup.Apply(context); } 

Questo creerà la tabella “Shape” con 2 righe denominate Square e Round, con il relativo vincolo di chiave esterna nella tabella “Foo”

È necessario aggiungere : byte davanti alla dichiarazione enum :

 enum MyFieldEnum : byte{ one = 1, two = 2, three = 4 } 

Nel database, dovresti vedere TINYINT e non c’è bisogno di lanciare!

Alberto Monteiro ha risposto molto bene. Ho dovuto apportare alcune modifiche per farlo funzionare con core EF.

Rinominare il tuo enum e aggiungere decoratori di descrizione

 public enum FacultyEnum { [Description("English Professor")] Eng, [Description("Math Professor")] Math, [Description("Economics Professor")] Eco } 

Crea una class che rappresenti la tabella

 public class Faculty { private Faculty(FacultyEnum @enum) { Id = (int)@enum; Name = @enum.ToString(); Description = @enum.GetEnumDescription(); } protected Faculty() { } //For EF [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id { get; set; } [Required, MaxLength(100)] public string Name { get; set; } [MaxLength(100)] public string Description { get; set; } public static implicit operator Faculty(FacultyEnum @enum) => new Faculty(@enum); public static implicit operator FacultyEnum(Faculty faculty) => (FacultyEnum)faculty.Id; } 

Il tuo modello fa riferimento alla class

 public class ExampleClass { public virtual Faculty Faculty { get; set; } } 

Creare un metodo di estensione per ottenere la descrizione dai valori enum e seed

 using System; using System.ComponentModel; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Linq; public static class Extensions { public static string GetEnumDescription(this TEnum item) => item.GetType() .GetField(item.ToString()) .GetCustomAttributes(typeof(DescriptionAttribute), false) .Cast() .FirstOrDefault()?.Description ?? string.Empty; } 

Aggiungi il seme in YourDbContext.cs

 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().HasData(FacultyEnum.Eng, FacultyEnum.Math, FacultyEnum.Eco); } 

Aggiungi la tabella enum nel tuo DbContext

 public class MyClass : DbContext { public DbSet Examples { get; set; } public DbSet Facultys { get; set; } } 

Usalo

 var example = new ExampleClass(); example.Faculty = FacultyEnum.Eng; if (example.Faculty == FacultyEnum.Math) { //code } 

Ricordare

Se non si aggiunge virtual nella proprietà Faculty, è necessario utilizzare il metodo Include da DbSet per eseguire Eager Load

 var exampleFromDb = dbContext.Examples.Include(x => x.Faculty).SingleOrDefault(e => e.Id == 1); if (example.Faculty == FacultyEnum.Math) { //code } 

Se la proprietà Faculty è virtuale, basta usarla

 var exampleFromDb = dbContext.Examples.Find(1); if (example.Faculty == FacultyEnum.Math) { //code }