我已经跟踪MSDN如何处理EF6的Code First中的枚举.它起作用,但是在创建的表中引用枚举器的字段是一个简单的int.
我更喜欢生成第二个表,其值将遵循C#代码中枚举数的定义.因此,我不想仅在MSDN上的示例中获取与Department对应的表,而是还希望看到由Faculty中的项填充的第二个表.
public enum Faculty { Eng, Math, Eco } public partial class Department { [Key] public Guid ID { get; set; } [Required] public Faculty Name { get; set; } }
在研究这个问题时,我偶然发现了一个解决方案,它建议为枚举创建一个表并通过种子显式填充它.
在我看来,这是一种繁琐的方法和许多应该自动处理的工作.毕竟,系统知道构成枚举的实际值.从数据库的角度来看,它仍然是数据行,就像我创建的实体一样,但从OO方面来说,它实际上并不是一个数据 - 而是一种类型(松散表达),它可以假设一个有限的和预先知道的状态数.
是否建议"手动"填充表格的方法?
由于EF不会自动处理,是的,这是推荐的方法.
我建议您在文章中进行一些修改.
public enum FacultyEnum { Eng, Math, Eco }
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; }
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
protected override void Seed(Temp.MyClass context) { context.Facultys.SeedEnumValues(@enum => @enum); context.SaveChanges(); }
public class MyClass : DbContext { public DbSetExamples { get; set; } public DbSet Facultys { get; set; } }
var example = new ExampleClass(); example.Faculty = FacultyEnum.Eng; if (example.Faculty == FacultyEnum.Math) { //code }
如果未在Faculty属性中添加虚拟,则必须使用DbSet中的Include方法执行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回答我已经创建了泛型类,以防你有几个表.这里的通知是Id是TEnum的类型.以这种方式使用它将提供使用Enum声明属性类型的选项.
public class Question { public QuestionTypeEnum QuestionTypeId { get; set; } // field property public QuestionType QuestionType { get; set; } // navigation property }
默认情况下,枚举使用整数,因此db提供程序将创建具有"int"类型的字段.
EnumTable.cs
public class EnumTablewhere 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样式一样,那就是使用enum有一个属性,它将按实体框架存储为整数.
然后,如果您希望在数据库中创建和更新"枚举表",我建议使用nuget包https://github.com/timabell/ef-enum-to-lookup并在EF Migration种子中使用它方法例如:
public enum Shape { Square, Round } public class Foo { public int Id { get; set; } public Shape Shape { get; set; } } public class MyDbContext : DbContext { public DbSetFoos { get; set; } } using(var context = new MyDbContext()) { var enumToLookup = new EnumToLookup { TableNamePrefix = string.Empty, NameFieldLength = 50, UseTransaction = true }; enumToLookup.Apply(context); }
这将创建"Shape"表,其中包含名为Square和Round的2行,并在表"Foo"中使用相关的外键约束