在 EF 中使用枚举 类

Using enumeration classes in EF

我在我的域模型中使用基于 Jimmy Bogard 的 this 文章的枚举 classes。但是,EF 将 classes 视为实体并希望定义一个键。

有没有办法让 EF 像使用标准 C# 枚举一样存储枚举 classes 中的值?

这就是我目前实现枚举的方式class:

public class ReservationStatus : Enumeration
{
    public static readonly ReservationStatus Outstanding = new ReservationStatus(0, "Oustanding");
    public static readonly ReservationStatus Paid = new ReservationStatus(1, "Paid");
    public static readonly ReservationStatus Canceled = new ReservationStatus(2, "Canceled");
    public static readonly ReservationStatus Rejected = new ReservationStatus(3, "Rejected");

    private ReservationStatus() { }
    private ReservationStatus(int value, string displayName) : base(value, displayName) { }
}

public class Reservation : Entity<int>
{
    public ReservationStatus Status { get; set; }
}

我正在使用 EF 7 RC1。

在 EF6 中,您可以将 ReservationClass 配置为 ComplexType,忽略 DisplayName 属性 并映射 Value 属性。

不幸的是,根据 these design meeting notes

In the initial RTM of EF7 we are not planning to enable complex and/or value types.

换句话说,您不能在当前的 EF Core 中执行此操作。

对于那些使用 EF Core 遇到这个 很好引用 线程的人,我通常按其值存储自定义类型枚举(又名标识符)在数据库中使用类型转换。此扩展方法可用于方法 OnModelCreating(或实现 IEntityTypeConfiguration<T> 的 class):

internal static class EnumerationConfiguration
{
    public static void OwnEnumeration<TEntity, TEnum>(this EntityTypeBuilder<TEntity> builder,
        Expression<Func<TEntity, TEnum>> property)
        where TEntity : class
        where TEnum : Enumeration
    {
        builder
            .Property(property)
            .HasConversion(x => x.Id, x => Enumeration.FromId<TEnum>(x));
    }
}

之后,枚举属性可以配置如下:

internal class SpecimenConfiguration : IEntityTypeConfiguration<Specimen>
{
    public void Configure(EntityTypeBuilder<Specimen> builder)
    {
        builder.OwnEnumeration(x => x.Type);
    }
}

这种方法的好处是它只存储标识符(而不存储附加到 Enumeration 的给定派生 class 的其他属性)并支持子classing Enumeration.

缺点是通过 Enumeration.FromId<TEnum>(x) 大量使用反射。这个可以通过在这个方法中引入缓存来摊销,Jimmy Bogard的链接文章没有提供。

对于那些使用 EF Core 3.1 的人来说,有更好的方法来做到这一点。目标是建立一个包含列出的枚举的数据库 table。

(1) 定义枚举 table 的样子:

public virtual DbSet<ReservationStatus> ReservationStatuses { get; set; }
 
public void Configure(EntityTypeBuilder<ReservationStatus> builder)
{
    builder.HasKey(x => x.Id);
    builder.Property(x => x.Id).HasDefaultValue(1).ValueGeneratedNever().IsRequired();
    builder.Property(x => x.Name).IsRequired();
}

(2) 定义值在保留实体中的关联方式

 public void Configure(EntityTypeBuilder<Reservation> builder)
 {
     builder.Property(x => x.ReservationStatusId).IsRequired();
     builder.HasOne(x => x.ReservationStatus)
         .WithMany()
         .HasForeignKey(x => x.ReservationStatusId);
 }

(3) 为枚举设定种子 table

if (!await RevervationSatuses.AnyAsync())
{
    RevervationSatuses.AddRange(Enumeration.GetAll<RevervationSatus>());
    await SaveChangesAsync();
}