【问题标题】:How to seed an enum in Entity Framework Core 2.1如何在 Entity Framework Core 2.1 中播种枚举
【发布时间】:2019-05-06 07:27:42
【问题描述】:

我是 EF Core 的新手,正在尝试播种枚举。

根据Data Seeding,此功能是 EF Core 2.1 的新增功能。

我查看了几个解决方案,包括这个 SO solution by Blake Mumford,但这对我不起作用,因为枚举不是引用类型。

我的目标(在迁移的帮助下)是让 Category 枚举被填充到一个名为 Category 的新 SQL 表中,并让我的 Payment 表包含一个将 Category 表作为外键引用的列。

任何帮助将不胜感激。谢谢。

public partial class Payment
{
    public int PaymentId { get; set; }
    public DateTime PostedDate { get; set; }
    public string Vendor { get; set; }
    public decimal Amount { get; set; }

    public virtual Category Category { get; set; }
}

public enum Category
{
    Restaurants,
    Groceries,
    [Display(Name = "Home Goods")]
    HomeGoods,
    Entertainment
}

public partial class MyDbContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Error: The type Category must be a reference type in order to use it as parameter TEntity in the 
        // genric type or method ModelBuilder.Entity<TEntity>()

        modelBuilder.Entity<Category>().HasData(Category.Restaurants, 
                                                Category.Groceries, 
                                                Category.HomeGoods, 
                                                Category.Entertainment);
    }
}

【问题讨论】:

    标签: asp.net entity-framework asp.net-core .net-core entity-framework-core


    【解决方案1】:

    这就是我所做的,希望它适用于您的环境。

    环境

    项目框架

    • .NetCore 3.0

    掘金:

    1. EFCore 3.1.2
    2. EFCore.Design 3.1.2
    3. EFCore.Tools 3.1.2
    4. EFCore.Relational 3.1.2
    5. EFCore.SqlServer 3.1.2

    实施

    1. 添加 OnModelCreating

      public partial class MyDbContext : DbContext
      {
          protected override void OnModelCreating(ModelBuilder modelBuilder)
          {
              // Error: The type Category must be a reference type in order to use it as parameter TEntity in the 
              // genric type or method ModelBuilder.Entity<TEntity>()
      
              modelBuilder.Entity<UserRole>().HasData(EnumFunctions.GetModelsFromEnum<UserRole, UserRoleEnum>());
          }
      }
      
    2. 创建一个通用枚举函数

      public static class EnumFunctions
      {
          public static IEnumerable<TModel> GetModelsFromEnum<TModel, TEnum>() where TModel : IEnumModel<TModel, TEnum>, new()
          {
              var enums = new List<TModel>();
              foreach (var enumVar in (TEnum[])Enum.GetValues(typeof(TEnum)))
              {
                  enums.Add(new TModel
                  {
                      Id = enumVar,
                      Name = enumVar.ToString()
                  });
              }
      
              return enums;
          }
      }
      
    3. 创建接口

      public interface IEnumModel<TModel, TModelIdType>
      {
          TModelIdType Id { get; set; }
          string Name { get; set; }
      }
      
    4. 将接口应用到模型

      [Table("UserRoles")]
      public class UserRole : IEnumModel<UserRole, UserRoleEnum>
      {
          [Key]
          public UserRoleEnum Id { get; set; }
          public string Name { get; set; }       
      }
      
    5. 添加您的迁移

      PM> add-migration SeedUserRoleTable
      

    您应该会看到添加的迁移

    1. 使用种子信息更新数据库

      PM> update-database
      

    【讨论】:

      【解决方案2】:

      在我的 Entities 文件夹下,我添加了 Enumerations 文件夹,我有这个:

      public class UserStatus : Enumeration
          {
      
              public static readonly UserStatus New = new UserStatus(1, "New");
              public static readonly UserStatus UnderReview = new UserStatus(2, "UnderReview");
              public static readonly UserStatus Customer = new UserStatus(3, "Customer");
              public static readonly UserStatus Approved = new UserStatus(4, "Approved");
              public static readonly UserStatus Declined = new UserStatus(5, "Declined");
      
              public UserStatus(int id, string name)
                          : base(id, name)
              {
              }
          }
      

      在我的 DataContext.cs 中,我只是使用它来播种数据:

       modelBuilder.Entity<UserStatus>().HasData(Enumeration.GetAll<UserStatus>());
      

      UserStatus 未在 DataContext.cs 中声明为 DbSet

      .NET Core 3.1

      【讨论】:

        【解决方案3】:

        您不能将枚举类型的值植入数据库,因为枚举不是实体类型,因此首先不会进入数据库。换句话说,不会有Categories 表,因此将值播种到那个不存在的表中是没有意义的。

        如果你想真正将你的类别持久化在你的数据库中,那么你需要创建一个类似的类:

        public class Category
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
        

        【讨论】:

        • 我想我明白你在说什么,但从数据库的角度来看,在代码中有一个 Category 枚举感觉不正确,它将作为字符串存储在我的 Payment桌子。从数据库的角度来看,这应该是通过外键引用 Category 表的 Id 字段。我找到了一个解决方案 (stackoverflow.com/a/52498981/4522506),在 OnModelCreating 中,您使用值转换,这将允许您将类别枚举映射到我的付款表中的 ID 或字符串,但这仍然无法处理播种。
        • 我同意。它应该是一个外键,这就是为什么它应该是一个class而不是一个enum。值转换器对您没有帮助,因为您无法将值投影到不同的表中。如果您坚持将其保留为枚举,则别无选择,只能将其作为值列。
        • 但如果我将其设为类而不是枚举,我将如何进行比较,例如:.Where(p => p.Category == Category.Entertainment)。此外,C# 将如何知道存储在数据库中的所有这些类别。这似乎是一种解决方法,对于应该自然是枚举的东西被表示为一个类,感觉并不自然。说了这么多,什么是最常见的 EF 解决方案,因为我是 EF 的新手。人们是否大多忽略了如何使用迁移构建数据库,而只是接受枚举只是在数据库中作为值列创建的事实?
        • 你想要两个相互矛盾的东西。枚举的全部意义在于它是定义的、不变的值的枚举。因此,将其持久化到数据库之类的东西是没有意义的,其中重点是允许数据的可变性。如果您想在数据库中使用它,那么您将不再具有明确定义的值范围,因此无法静态引用它们。选择一种方法,不要再试图将两者结合起来。
        猜你喜欢
        • 1970-01-01
        • 2017-12-22
        • 2020-05-23
        • 2018-12-04
        • 2018-09-29
        • 2021-06-30
        • 2016-05-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多