如何在EF Core Code First中创建与枚举对应的表?

Tim*_*ell 7 c# enums entity-framework-core

如何将EF Core数据库上下文中使用的枚举转换为查找表并添加相关外键?


Pao*_*oni 34

通过结合使用这两个 EF Core 功能,您可以在代码中使用枚举并在数据库中使用查找表:

  • 值转换- 在读取/写入数据库时​​将枚举转换为 int
  • 数据播种- 在迁移中添加数据库中的枚举值

下面是一个数据模型示例:

public class Wine
{
    public int WineId { get; set; }
    public string Name { get; set; }

    public WineVariantId WineVariantId { get; set; }
    public WineVariant WineVariant { get; set; }
}

public enum WineVariantId : int
{
    Red = 0,
    White = 1,
    Rose = 2
}

public class WineVariant
{
    public WineVariantId WineVariantId { get; set; }
    public string Name { get; set; }

    public List<Wine> Wines { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

DbContext您可以在此处配置价值转换和数据播种:

public class WineContext : DbContext
{
    public DbSet<Wine> Wines { get; set; }
    public DbSet<WineVariant> WineVariants { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=wines.db");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder
            .Entity<Wine>()
            .Property(e => e.WineVariantId)
            .HasConversion<int>();

        modelBuilder
            .Entity<WineVariant>()
            .Property(e => e.WineVariantId)
            .HasConversion<int>();

        modelBuilder
            .Entity<WineVariant>().HasData(
                Enum.GetValues(typeof(WineVariantId))
                    .Cast<WineVariantId>()
                    .Select(e => new WineVariant()
                    {
                        WineVariantId = e,
                        Name = e.ToString()
                    })
            );
    }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以在代码中使用枚举值,如下所示:

db.Wines.Add(new Wine
{
    Name = "Gutturnio",
    WineVariantId = WineVariantId.Red,
});

db.Wines.Add(new Wine
{
    Name = "Ortrugo",
    WineVariantId = WineVariantId.White,
});
Run Code Online (Sandbox Code Playgroud)

这是您的数据库将包含的内容:

WineVariants 表

酒桌

我发布了完整的示例作为要点:https : //gist.github.com/paolofulgoni/825bef5cd6cd92c4f9bbf33f603af4ff

  • 您如何解释未来迁移中枚举的变化?假设您要在枚举位置 3(当前为玫瑰色)中插入一条记录,以便 wine.rose = 4 和 wine.blend = 3。创建的迁移会更新该列,因此我所有的玫瑰酒现在都是混合酒,并且玫瑰色添加在结尾。:( (3认同)
  • @Itanex如果您故意更改元素的ID,我认为手动更改迁移是公平的。如果您想避免意外更改,那么在枚举中使用显式值可能会有所帮助,我将相应地更新示例 (3认同)

Kav*_*eri 6

这是另一个例子:

public class Weather {
        public int Id { get; init; }
        public WeatherType Type { get; init; }
    }

public enum WeatherType {
        Cloudy = 1,
        Sunny = 2,
        Rainy = 3,
    }
Run Code Online (Sandbox Code Playgroud)

您可以添加HasConversion一个单独的类,如下所示:

public class WeatherEntityTypeConfiguration : IEntityTypeConfiguration<Weather>
    {
        public void Configure(EntityTypeBuilder<Weather> builder)
        {
            builder.ToTable("Weather").HasKey(k => k.Id);

            builder.Property(p => p.Id).IsRequired();
            builder.Property(p => p.Type).HasConversion<int>().IsRequired(); 
            // builder.Property(p => p.Type).HasConversion<string>().IsRequired();
          
        }
    }
Run Code Online (Sandbox Code Playgroud)

注意:如果您使用HasConversion<int>()数据将存储在数据库中,integer但如果您使用HasConversion<string>()数据将存储为字符串(在本例中:阴天、晴天或雨天)