Как создать таблицу, соответствующую перечислению в EF6 Code First?

Я следил за MSDN, как обрабатывать enums в Code First для EF6. Он работал, как предполагалось, но поле в созданной таблице, которое ссылается на перечислитель, является простым int .

Я бы предпочел создать вторую таблицу, значения которой будут следовать определению перечислителя в коде C #. Таким образом, вместо того, чтобы получать таблицу, соответствующую Департаменту в примере на MSDN, мне также хотелось бы увидеть вторую таблицу, заполненную предметами факультета .

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

Исследуя проблему, я наткнулся на решение , которое предлагает создать таблицу для enums и заполнить ее явным образом посевом.

Это кажется мне громоздким подходом и большой работой, которую нужно решать автоматически. В конце концов, система знает, какие фактические значения представляют собой перечисление. С точки зрения БД это все еще строки данных, так же как сущности, которые я создаю, но с точки зрения ОО, это не действительно данные – скорее тип (слабо выраженный), который может принимать конечное и заранее известное количество состояний.

Рекомендуется ли использовать таблицу «вручную»?

Поскольку EF не обрабатывает его автоматически, да , это рекомендуемый способ.

Я предлагаю некоторые изменения в статье, которые вы предоставили.

Переименуйте переименование

 public enum FacultyEnum { Eng, Math, Eco } 

Создайте class, представляющий таблицу

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

Ваша модель ссылается на class

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

Создайте метод расширения, чтобы получить описание из перечислений и значений семени

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

Добавить семя в Configuration.cs

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

Добавьте таблицу enums в свой DbContext

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

Используй это

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

Запомнить

Если вы не добавляете виртуальную собственность в свойство Faculty, вы должны использовать метод Include из DbSet для выполнения Eager Load

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

Если свойство Faculty является виртуальным, просто используйте его

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

Основываясь на ответе @Alberto Monteiro, я создал общий class в случае, если у вас несколько таблиц. Обратите внимание, что Id – это тип TEnum. Использование его таким образом обеспечит возможность использования Enum для объявления типа свойства.

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

По умолчанию Enum использует целые числа, поэтому поставщик db создаст поле с типом «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)}"); } } } 

Теперь вы можете наследовать 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! } 

Выделите значения

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

Другая возможность, если вы хотите, чтобы ваша модель была проще, чем стиль POCO, заключается в использовании enums, имеет свойство, которое будет храниться как целое по структуре сущности.

Затем, если вы хотите, чтобы в вашей базе данных были созданы и обновлены «таблицы перечислений», я рекомендую использовать пакет nuget https://github.com/timabell/ef-enum-to-lookup и использовать его в семестре миграции EF метод, например:

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

Это создаст таблицу «Shape» с двумя строками с именем «Квадрат» и «Круглый» с соответствующим ограничением внешнего ключа в таблице «Foo»,

Вы должны добавить : byte перед объявлением enum :

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

В базе данных вы должны увидеть TINYINT и не нужно кастинг!

Альберто Монтейро ответил на это очень хорошо. Мне пришлось внести несколько корректировок, чтобы заставить его работать с kernelм EF.

Переименуйте свой enum и добавьте декораторы описания

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

Создайте class, представляющий таблицу

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

Ваша модель ссылается на class

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

Создайте метод расширения, чтобы получить описание из перечислений и значений семени

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

Добавьте семя в YourDbContext.cs

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

Добавьте таблицу enums в свой DbContext

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

Используй это

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

Запомнить

Если вы не добавляете виртуальную собственность в свойство Faculty, вы должны использовать метод Include из DbSet для выполнения Eager Load

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

Если свойство Faculty является виртуальным, просто используйте его

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

Зачем использовать StringBuffer в Java вместо оператора конкатенации строк

std :: transform () и toupper (), нет соответствующей функции

Android sp vs dp text – что бы регулировать «масштаб» и что является философией поддержки

Как разрешить Java UnknownHostKey при использовании библиотеки SFTP JSch?

Как сделать загрузчик Windows по умолчанию?

Сделать планировщик задач Windows оповестите меня об ошибке

Есть ли способ подделать двойной (второй) монитор

как регистрировать SQL-команды в Spring-Boot

Список телефонных номеров кодов стран

Наиболее эффективный способ случайного выбора набора различных целых чисел

Где я могу указать название своей компании?

Двойная загрузка Linux / Windows 7

Как получить позицию столбца каретки (не пикселей) в текстовом поле, в символах, с самого начала?

Windows 7 – отсутствует свободное место на жестком диске

CURRENT_DATE / CURDATE () не работает как значение DATE по умолчанию

Давайте будем гением компьютера.