.Net Core 2.1 似乎忽略了 modelBuilder.Entity<TEntity>().HasData

use*_*791 5 c# enums entity-framework entity-framework-core .net-core

我有一个包含模型、服务和 api 项目的 .net 核心项目。我对这个项目的最初目标是让枚举以更“代码优先”的方式工作。我只想能够修改枚举并相应地更新数据库和查找表。在花了太多时间试图弄清楚如何做到这一点之后,我决定创建一个特殊的枚举类并使用“HasData”手动为其设定种子。我以前做过这个,没有遇到过问题。我做的最后一个项目是 .Net Core 2.1。该项目使用的是 2.2。我不知道我是否发现了一个奇怪的错误,或者我只是做错了什么。我的“服务”项目是 DbContext 所在和大部分相关代码所在的地方。

我有一个看起来像的模型:

public class Employee : IEmployee
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Display(Name = "Id")]
    public int Id { get; set; }

    [StringLength(512, ErrorMessage = "The first name cannot be longer than 512 characters")]
    [Display(Name = "First Name")]
    [Required]
    public string FirstName { get; set; }

    [StringLength(512, ErrorMessage = "The last name cannot be longer than 512 characters")]
    [Display(Name = "Last Name")]
    [Required]
    public string LastName { get; set; }

    public Department Department { get; set; }

}
Run Code Online (Sandbox Code Playgroud)

它有一个枚举:

public enum Department{

    [Description("Sales")]
    Sales = 1,

    [Description("Customer Service")]
    CustomerService = 2,

    [Description("Technical Support")]
    TechnicalSupport = 3
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个对应于枚举的模型,如下所示:

[Table("Department")]
public class DepartmentEnum : EnumBase<Department>
{
    public DepartmentEnum()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

它有一个看起来像这样的基类:

public class EnumBase<TEnum> where TEnum : struct
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public virtual int Id { get; set; }

    [Required]
    [MaxLength(100)]
    public virtual string Name { get; set; }

    [MaxLength(100)]
    public virtual string Description { get; set; }

    public virtual bool Deleted { get; set; } = false;
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个如下所示的 DbContext:

public class ApplicationDbContext : IdentityDbContext<AppUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options){}

    public DbSet<Employee> Employees { get; set; }

    public DbSet<DepartmentEnum> Departments { get; set; }

    protected internal virtual void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<DepartmentEnum>().HasData(
            new DepartmentEnum { Id = 1, Name = "Sales", Description = "Sales", Deleted = false },
            new DepartmentEnum { Id = 2, Name = "Customer Service", Description = "Customer Service", Deleted = false },
            new DepartmentEnum { Id = 3, Name = "TechnicalSupport", Description = "Technical Support", Deleted = false }
        );

    }
}
Run Code Online (Sandbox Code Playgroud)

在该OnModelCreating部分中,我正在播种我想要在此表中的数据。因为服务项目不能直接启动,也不能学习它的连接字符串,所以我创建了一个DbContextFactory继承自IDesignTimeDbContextFactory<ApplicationDbContext>它的看起来像这样:

public class DbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
    public ApplicationDbContext CreateDbContext(string[] args)
    {
        //uncomment this line if you need to debug this code
        //then choose yes and create a new instance of visual
        //studio to step through the code
        //Debugger.Launch();

        var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
        builder
            .UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=EnumSeeder;Trusted_Connection=True;MultipleActiveResultSets=true");

        //get the dbContext
        var context = new ApplicationDbContext(builder.Options);

        return context;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行时,add-migration InitialCreate我希望看到我的模型数据反映在迁移文件中。当我查看部门表时,我看到的是:

migrationBuilder.CreateTable(
    name: "Department",
    columns: table => new
    {
        Id = table.Column<int>(nullable: false)
            .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
        Name = table.Column<string>(maxLength: 100, nullable: false),
        Description = table.Column<string>(maxLength: 100, nullable: true),
        Deleted = table.Column<bool>(nullable: false)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_Department", x => x.Id);
    });
Run Code Online (Sandbox Code Playgroud)

无论我做什么,创作的“HasData”药水都不会存在。我曾尝试将 db 上下文切换到简单的 old DbContext。我尝试通过首先添加员工表然后返回并添加部门表作为第二次迁移来更改事件的顺序。似乎我所做的任何事情都不会使迁移包含种子数据。

谁能发现我的问题?

Iva*_*oev 4

您应该注意编译器警告。

这里

protected internal virtual void OnModelCreating(ModelBuilder modelBuilder)
Run Code Online (Sandbox Code Playgroud)

您正在隐藏基本OnModelCreating方法(必须有一个编译器警告告诉您)。当然,EF Core 基础结构不会调用您的方法,而是调用DbContext类中定义的方法。

因此,您在其中放置的任何内容都没有效果 - 该Department表是根据 EF Core 约定创建的,当然没有数据种子。

将方法签名更改为

protected override void OnModelCreating(ModelBuilder modelBuilder)
Run Code Online (Sandbox Code Playgroud)

并确保致电

base.OnModelCreating(modelBuilder);
Run Code Online (Sandbox Code Playgroud)

一开始。IdentityContext当您继承(或任何除 this 之外的任何基上下文类DbContext)时,这一点尤其重要。