如何在 EF6 Code First 中创建对应于枚举的 table?
How to create a table corresponding to enum in EF6 Code First?
我已经按照 MSDN 了解如何处理 Code First for EF6 中的枚举。它工作正常,正如预期的那样 但是 创建的 table 中引用枚举器的字段是一个简单的 int.
我希望生成第二个 table,其值将遵循 C# 代码中枚举数的定义。因此,在 MSDN 的示例中,我不想只获得对应于 Department 的 table,我还希望看到第二个 table 由来自教师.
public enum Faculty { Eng, Math, Eco }
public partial class Department
{
[Key] public Guid ID { get; set; }
[Required] public Faculty Name { get; set; }
}
研究这个问题时,我偶然发现了一个 solution,它建议为枚举创建一个 table 并通过播种显式填充它。
在我看来,这是一种繁琐的方法,并且有很多工作应该自动处理。毕竟,系统知道构成枚举的实际值是什么。从数据库的角度来看,它仍然是数据行,就像我创建的实体一样,但从面向对象的角度来看,它并不是真正的数据——而是一种类型(松散地表达),它可以假设有限的和事先已知的状态数。
填充 table "manually" 的方法是否推荐?
由于 EF 不会自动处理它,是,这是推荐的方式。
我建议对您提供的文章进行一些修改。
重命名您的枚举
public enum FacultyEnum { Eng, Math, Eco }
创建代表 table
的 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<TEnum>(this TEnum item)
=> item.GetType()
.GetField(item.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>()
.FirstOrDefault()?.Description ?? string.Empty;
public static void SeedEnumValues<T, TEnum>(this IDbSet<T> dbSet, Func<TEnum, T> converter)
where T : class => Enum.GetValues(typeof(TEnum))
.Cast<object>()
.Select(value => converter((TEnum)value))
.ToList()
.ForEach(instance => dbSet.AddOrUpdate(instance));
}
在Configuration.cs
中添加种子
protected override void Seed(Temp.MyClass context)
{
context.Facultys.SeedEnumValues<Faculty, FacultyEnum>(@enum => @enum);
context.SaveChanges();
}
在您的 DbContext
中添加枚举 table
public class MyClass : DbContext
{
public DbSet<ExampleClass> Examples { get; set; }
public DbSet<Faculty> 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
}
另一种可能性,如果你想让你的模型更简单,POCO 风格,使用枚举作为 属性,它将被 entity framework 作为整数存储。
然后,如果您希望在您的数据库中创建和更新 "enum tables",我建议使用 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<Foo> Foos { get; set; }
}
using(var context = new MyDbContext())
{
var enumToLookup = new EnumToLookup
{
TableNamePrefix = string.Empty,
NameFieldLength = 50,
UseTransaction = true
};
enumToLookup.Apply(context);
}
这将创建具有 2 行的 "Shape" table,分别命名为 Square 和 Round,并在 table "Foo"
中使用相关的外键约束
基于@Alberto Monteiro 的回答,我创建了通用 class 以防您有多个表。这里需要注意的是,Id 是 TEnum 的类型。以这种方式使用它将提供使用 Enum 声明 属性 类型的选项。
public class Question
{
public QuestionTypeEnum QuestionTypeId { get; set; } // field property
public QuestionType QuestionType { get; set; } // navigation property
}
默认枚举使用整数,因此数据库提供程序将创建 "int" 类型的字段。
EnumTable.cs
public class EnumTable<TEnum>
where TEnum : struct
{
public TEnum Id { get; set; }
public string Name { get; set; }
protected EnumTable() { }
public EnumTable(TEnum enumType)
{
ExceptionHelpers.ThrowIfNotEnum<TEnum>();
Id = enumType;
Name = enumType.ToString();
}
public static implicit operator EnumTable<TEnum>(TEnum enumType) => new EnumTable<TEnum>(enumType);
public static implicit operator TEnum(EnumTable<TEnum> status) => status.Id;
}
ExceptionHelpers.cs
static class ExceptionHelpers
{
public static void ThrowIfNotEnum<TEnum>()
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<QuestionTypeEnum>
{
public QuestionType(QuestionTypeEnum enumType) : base(enumType)
{
}
public QuestionType() : base() { } // should excplicitly define for EF!
}
为值设定种子
context.QuestionTypes.SeedEnumValues<QuestionType, QuestionTypeEnum>(e => new QuestionType(e));
您应该在 enum
声明前添加 : byte
:
enum MyFieldEnum : byte{
one = 1,
two = 2,
three = 4
}
在数据库中,您应该会看到 TINYINT
而无需转换 !
更新:我发现了一种在 EntityFrameworkCore 5.0.8 中运行良好的更好方法
将 JsonConverter 属性添加到您的枚举中
[Newtonsoft.Json.JsonConverter(typeof(StringEnumConverter))]
public enum FacultyEnum
{
[EnumMember(Value = "English Professor")]
Eng,
[EnumMember(Value = "Math Professor")]
Math,
[EnumMember(Value = "Economics Professor")]
Eco
}
创建一个class代表table
public class Faculty
{
public int Id { get; set; }
public string Name { get; set; }
public FacultyEnum Description { get; set; }
}
在 DbContext 的 OnModelCreating 中使用 Fluent API 以使用枚举字符串并设置检查约束
var enumToString = new EnumToStringConverter<FacultyEnum>();
modelBuilder.Entity<Faculty>(entity =>
{
entity.ToTable(nameof(FacultyMembers));
//convert enums to string
entity.Property(e => e.Description).HasConversion(enumToString);
//build check constraint from enum
var allowedEnumStrings = string.Join(',',
typeof(Faculty).GetMembers()
.Select(x => x.GetCustomAttribute(typeof(EnumMemberAttribute), false)).Where(x => x != null)
.Select(x => $"'{((EnumMemberAttribute)x).Value}'"));
entity.HasCheckConstraint($"CK_{nameof(FacultyMembers)}_{nameof(Faculty.Description)}", $"{nameof(Faculty.Description)} in ({allowedEnumStrings})");
});
老办法
Alberto Monteiro 回答得很好。我必须进行一些调整才能使其与 EF 核心一起使用。
重命名您的枚举并添加描述装饰器
public enum FacultyEnum
{
[Description("English Professor")]
Eng,
[Description("Math Professor")]
Math,
[Description("Economics Professor")]
Eco
}
创建代表 table
的 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<TEnum>(this TEnum item)
=> item.GetType()
.GetField(item.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>()
.FirstOrDefault()?.Description ?? string.Empty;
}
在YourDbContext.cs
中添加种子
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Faculty>().HasData(FacultyEnum.Eng, FacultyEnum.Math, FacultyEnum.Eco);
}
在您的 DbContext
中添加枚举 table
public class MyClass : DbContext
{
public DbSet<ExampleClass> Examples { get; set; }
public DbSet<Faculty> Facultys { get; set; }
}
使用它
var example = new ExampleClass();
example.Faculty = FacultyEnum.Eng;
if (example.Faculty == FacultyEnum.Math)
{
//code
}
记住
如果不在 Faculty 属性 中添加 virtual,则必须使用 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
}
出色的@AlbertoMonterio!为了让它与 ASP.NET CORE / EF Core 一起工作,我对 Alberto 的解决方案做了一些调整。
为简洁起见,下面仅显示修改:
创建扩展方法以从枚举和种子值中获取描述
using System;
using System.ComponentModel;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
using Microsoft.EntityFrameworkCore; //added
using Microsoft.EntityFrameworkCore.Metadata.Builders; //added
public static class Extensions
{
//unchanged from alberto answer
public static string GetEnumDescription<TEnum>(this TEnum item)
=> item.GetType()
.GetField(item.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>()
.FirstOrDefault()?.Description ?? string.Empty;
//changed
public static void SeedEnumValues<T, TEnum>(this ModelBuilder mb, Func<TEnum, T> converter)
where T : class => Enum.GetValues(typeof(TEnum))
.Cast<object>()
.Select(value => converter((TEnum)value))
.ToList()
.ForEach(instance => mb.Entity<T>().HasData(instance));
}
添加种子在Configuration.cs
将种子添加到 DataContext
的 OnModelCreating
protected override void OnModelCreating(ModelBuilder builder)
{
builder.SeedEnumValues<Faculty, EnumEntityRole>(e => e);
}
另一种在 EF Core 中有效(对我来说感觉更简单)的方法:
你的枚举
public enum Color
{
Red = 1,
Blue = 2,
Green = 3,
}
数据库表
public class CustomObjectDto
{
public int ID { get; set; }
// ... other props
public Color ColorID { get; set; }
public ColorDto ColorDto { get; set; }
}
public class ColorDto
{
public Color ID { get; set; }
public string Name { get; set; }
}
你的 DbContext
public class Db : DbContext
{
public Db(DbContextOptions<Db> options) : base(options) { }
public DbSet<CustomObjectDto> CustomObjects { get; set; }
public DbSet<ColorDto> Colors { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Seed database with all Colors
foreach (Color color in Enum.GetValues(typeof(Color)).Cast<Color>())
{
ColorDto colorDto = new ColorDto
{
ID = color,
Name = color.ToString(),
};
modelBuilder.Entity<ColorDto>().HasData(colorDto);
}
}
}
在代码中,我基本上只使用枚举 Color(从不使用 ColorDto)。但是在 'CustomObjects' table 中为 sql 查询和视图提供带有 FK 的 'Colors' table 仍然很好。
我参加聚会可能有点晚了,但我没有在这里找到我要找的答案。
在 EntityFramework 文档中查找时我找到了解决方案,这是 Value Conversions
中的第一个示例
有了这个,如果你愿意,你可以做一个很好的扩展方法。即
public static void HasEnum<TEntity, TProperty>(this EntityTypeBuilder<TEntity> entityBuilder, Expression<Func<TEntity, TProperty>> propertyExpression)
where TEntity : class
where TProperty : Enum
{
entityBuilder.Property(propertyExpression)
.HasConversion(
v => v.ToString(),
v => (TProperty)Enum.Parse(typeof(TProperty), v)
);
}
然后在您的 OnModelCreating 中使用它:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourEntity>()
.HasEnum(e => e.YourProperty);
}
我已经按照 MSDN 了解如何处理 Code First for EF6 中的枚举。它工作正常,正如预期的那样 但是 创建的 table 中引用枚举器的字段是一个简单的 int.
我希望生成第二个 table,其值将遵循 C# 代码中枚举数的定义。因此,在 MSDN 的示例中,我不想只获得对应于 Department 的 table,我还希望看到第二个 table 由来自教师.
public enum Faculty { Eng, Math, Eco }
public partial class Department
{
[Key] public Guid ID { get; set; }
[Required] public Faculty Name { get; set; }
}
研究这个问题时,我偶然发现了一个 solution,它建议为枚举创建一个 table 并通过播种显式填充它。
在我看来,这是一种繁琐的方法,并且有很多工作应该自动处理。毕竟,系统知道构成枚举的实际值是什么。从数据库的角度来看,它仍然是数据行,就像我创建的实体一样,但从面向对象的角度来看,它并不是真正的数据——而是一种类型(松散地表达),它可以假设有限的和事先已知的状态数。
填充 table "manually" 的方法是否推荐?
由于 EF 不会自动处理它,是,这是推荐的方式。
我建议对您提供的文章进行一些修改。
重命名您的枚举
public enum FacultyEnum { Eng, Math, Eco }
创建代表 table
的 classpublic 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<TEnum>(this TEnum item)
=> item.GetType()
.GetField(item.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>()
.FirstOrDefault()?.Description ?? string.Empty;
public static void SeedEnumValues<T, TEnum>(this IDbSet<T> dbSet, Func<TEnum, T> converter)
where T : class => Enum.GetValues(typeof(TEnum))
.Cast<object>()
.Select(value => converter((TEnum)value))
.ToList()
.ForEach(instance => dbSet.AddOrUpdate(instance));
}
在Configuration.cs
中添加种子protected override void Seed(Temp.MyClass context)
{
context.Facultys.SeedEnumValues<Faculty, FacultyEnum>(@enum => @enum);
context.SaveChanges();
}
在您的 DbContext
中添加枚举 tablepublic class MyClass : DbContext
{
public DbSet<ExampleClass> Examples { get; set; }
public DbSet<Faculty> 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
}
另一种可能性,如果你想让你的模型更简单,POCO 风格,使用枚举作为 属性,它将被 entity framework 作为整数存储。
然后,如果您希望在您的数据库中创建和更新 "enum tables",我建议使用 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<Foo> Foos { get; set; }
}
using(var context = new MyDbContext())
{
var enumToLookup = new EnumToLookup
{
TableNamePrefix = string.Empty,
NameFieldLength = 50,
UseTransaction = true
};
enumToLookup.Apply(context);
}
这将创建具有 2 行的 "Shape" table,分别命名为 Square 和 Round,并在 table "Foo"
中使用相关的外键约束基于@Alberto Monteiro 的回答,我创建了通用 class 以防您有多个表。这里需要注意的是,Id 是 TEnum 的类型。以这种方式使用它将提供使用 Enum 声明 属性 类型的选项。
public class Question
{
public QuestionTypeEnum QuestionTypeId { get; set; } // field property
public QuestionType QuestionType { get; set; } // navigation property
}
默认枚举使用整数,因此数据库提供程序将创建 "int" 类型的字段。
EnumTable.cs
public class EnumTable<TEnum>
where TEnum : struct
{
public TEnum Id { get; set; }
public string Name { get; set; }
protected EnumTable() { }
public EnumTable(TEnum enumType)
{
ExceptionHelpers.ThrowIfNotEnum<TEnum>();
Id = enumType;
Name = enumType.ToString();
}
public static implicit operator EnumTable<TEnum>(TEnum enumType) => new EnumTable<TEnum>(enumType);
public static implicit operator TEnum(EnumTable<TEnum> status) => status.Id;
}
ExceptionHelpers.cs
static class ExceptionHelpers
{
public static void ThrowIfNotEnum<TEnum>()
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<QuestionTypeEnum>
{
public QuestionType(QuestionTypeEnum enumType) : base(enumType)
{
}
public QuestionType() : base() { } // should excplicitly define for EF!
}
为值设定种子
context.QuestionTypes.SeedEnumValues<QuestionType, QuestionTypeEnum>(e => new QuestionType(e));
您应该在 enum
声明前添加 : byte
:
enum MyFieldEnum : byte{
one = 1,
two = 2,
three = 4
}
在数据库中,您应该会看到 TINYINT
而无需转换 !
更新:我发现了一种在 EntityFrameworkCore 5.0.8 中运行良好的更好方法
将 JsonConverter 属性添加到您的枚举中
[Newtonsoft.Json.JsonConverter(typeof(StringEnumConverter))]
public enum FacultyEnum
{
[EnumMember(Value = "English Professor")]
Eng,
[EnumMember(Value = "Math Professor")]
Math,
[EnumMember(Value = "Economics Professor")]
Eco
}
创建一个class代表table
public class Faculty
{
public int Id { get; set; }
public string Name { get; set; }
public FacultyEnum Description { get; set; }
}
在 DbContext 的 OnModelCreating 中使用 Fluent API 以使用枚举字符串并设置检查约束
var enumToString = new EnumToStringConverter<FacultyEnum>();
modelBuilder.Entity<Faculty>(entity =>
{
entity.ToTable(nameof(FacultyMembers));
//convert enums to string
entity.Property(e => e.Description).HasConversion(enumToString);
//build check constraint from enum
var allowedEnumStrings = string.Join(',',
typeof(Faculty).GetMembers()
.Select(x => x.GetCustomAttribute(typeof(EnumMemberAttribute), false)).Where(x => x != null)
.Select(x => $"'{((EnumMemberAttribute)x).Value}'"));
entity.HasCheckConstraint($"CK_{nameof(FacultyMembers)}_{nameof(Faculty.Description)}", $"{nameof(Faculty.Description)} in ({allowedEnumStrings})");
});
老办法
Alberto Monteiro 回答得很好。我必须进行一些调整才能使其与 EF 核心一起使用。
重命名您的枚举并添加描述装饰器
public enum FacultyEnum
{
[Description("English Professor")]
Eng,
[Description("Math Professor")]
Math,
[Description("Economics Professor")]
Eco
}
创建代表 table
的 classpublic 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<TEnum>(this TEnum item)
=> item.GetType()
.GetField(item.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>()
.FirstOrDefault()?.Description ?? string.Empty;
}
在YourDbContext.cs
中添加种子protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Faculty>().HasData(FacultyEnum.Eng, FacultyEnum.Math, FacultyEnum.Eco);
}
在您的 DbContext
中添加枚举 tablepublic class MyClass : DbContext
{
public DbSet<ExampleClass> Examples { get; set; }
public DbSet<Faculty> Facultys { get; set; }
}
使用它
var example = new ExampleClass();
example.Faculty = FacultyEnum.Eng;
if (example.Faculty == FacultyEnum.Math)
{
//code
}
记住
如果不在 Faculty 属性 中添加 virtual,则必须使用 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
}
出色的@AlbertoMonterio!为了让它与 ASP.NET CORE / EF Core 一起工作,我对 Alberto 的解决方案做了一些调整。
为简洁起见,下面仅显示修改:
创建扩展方法以从枚举和种子值中获取描述
using System;
using System.ComponentModel;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
using Microsoft.EntityFrameworkCore; //added
using Microsoft.EntityFrameworkCore.Metadata.Builders; //added
public static class Extensions
{
//unchanged from alberto answer
public static string GetEnumDescription<TEnum>(this TEnum item)
=> item.GetType()
.GetField(item.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>()
.FirstOrDefault()?.Description ?? string.Empty;
//changed
public static void SeedEnumValues<T, TEnum>(this ModelBuilder mb, Func<TEnum, T> converter)
where T : class => Enum.GetValues(typeof(TEnum))
.Cast<object>()
.Select(value => converter((TEnum)value))
.ToList()
.ForEach(instance => mb.Entity<T>().HasData(instance));
}
添加种子在Configuration.cs
将种子添加到 DataContext
的OnModelCreating
protected override void OnModelCreating(ModelBuilder builder)
{
builder.SeedEnumValues<Faculty, EnumEntityRole>(e => e);
}
另一种在 EF Core 中有效(对我来说感觉更简单)的方法:
你的枚举
public enum Color
{
Red = 1,
Blue = 2,
Green = 3,
}
数据库表
public class CustomObjectDto
{
public int ID { get; set; }
// ... other props
public Color ColorID { get; set; }
public ColorDto ColorDto { get; set; }
}
public class ColorDto
{
public Color ID { get; set; }
public string Name { get; set; }
}
你的 DbContext
public class Db : DbContext
{
public Db(DbContextOptions<Db> options) : base(options) { }
public DbSet<CustomObjectDto> CustomObjects { get; set; }
public DbSet<ColorDto> Colors { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Seed database with all Colors
foreach (Color color in Enum.GetValues(typeof(Color)).Cast<Color>())
{
ColorDto colorDto = new ColorDto
{
ID = color,
Name = color.ToString(),
};
modelBuilder.Entity<ColorDto>().HasData(colorDto);
}
}
}
在代码中,我基本上只使用枚举 Color(从不使用 ColorDto)。但是在 'CustomObjects' table 中为 sql 查询和视图提供带有 FK 的 'Colors' table 仍然很好。
我参加聚会可能有点晚了,但我没有在这里找到我要找的答案。
在 EntityFramework 文档中查找时我找到了解决方案,这是 Value Conversions
中的第一个示例有了这个,如果你愿意,你可以做一个很好的扩展方法。即
public static void HasEnum<TEntity, TProperty>(this EntityTypeBuilder<TEntity> entityBuilder, Expression<Func<TEntity, TProperty>> propertyExpression)
where TEntity : class
where TProperty : Enum
{
entityBuilder.Property(propertyExpression)
.HasConversion(
v => v.ToString(),
v => (TProperty)Enum.Parse(typeof(TProperty), v)
);
}
然后在您的 OnModelCreating 中使用它:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourEntity>()
.HasEnum(e => e.YourProperty);
}