建立自动迁移和种子,而不会破坏实体框架工具链

时间:2017-09-14 14:51:44

标签: c# asp.net-core-mvc entity-framework-core

不幸的是,Entity Framwork Core不再支持IDatabaseInitializer:所以没有DropCreateDatabaseAlways.Seed()DropCreateDatabaseIfModelChanges.Seed()。 : - (

所以那里的人写了很多东西:

  1. 如果不存在则创建数据库。
  2. 将数据库迁移到最新版本。
  3. DbContext的具体实例的帮助下,如果#1(作为数据库为空)应用种子数据。
  4. 我在Startup.Configure 末尾提出了以下行,其中IApplicationBuilder appIHostingEnvironment env被注入:

    using (var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        using (var context = scope.ServiceProvider.GetService<MyDbContext>())
        {
            var hasPendingMigrations = context.Database.GetPendingMigrations().Any();
            if (hasPendingMigrations) {
                var needsSeeding = !context.Database.GetAppliedMigrations().Any(); // No migration yet (no database or it's empty).
    
                context.Database.Migrate(); // Create/update schema (creates database if necessary).
    
                if (needsSeeding) {
                    Seed(context);
                    if (env.IsDevelopment()) {
                        SeedWithDummyData(context);
                    }
                }
            }
        }
    }
    

    但是将这些行放在Startup.Configure的末尾会破坏实体框架工具链:

    PM> Add-Migration MyMigration
    PM> Update-Datebase
    

    以及:

    PM> Update-Datebase NameOfPreviousMigration
    PM> Remove-Migration
    

    这些命令行开关使用方法Program.BuildWebHost()来调用我的StartupStartup.ConfigureServices()以及Startup.Configure()(即使不需要:{{3} }})。更糟糕的是,如果我打电话Remove-Migration,就会让粉丝点击粉丝:Remove-MigrationStartup.Configure()→迁移和种子(数据库是最新迁移=没有要移除的迁移)→错误:

      

    迁移&#39; 20170914084432_MyMigration&#39;已经应用于数据库。还原它然后再试一次。如果迁移已应用于其他数据库,请考虑使用新迁移恢复其更改。

    简单地说,如何从工具链中分别运行我的Migrate&amp; Seed内容告诉我Startup.Configure()的工具链?

    请注意:我不想使用IDesignTimeDbContextFactory因为......

1 个答案:

答案 0 :(得分:0)

经过几个小时的猜测和失败,我放弃了Startup课程!所以我现在使用RuntimeStartup用于运行时,并且几乎为空Startup用于所有设计时任务(脚手架和迁移):

public class Program
{
    public static void Main(string[] args)
    {
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<RuntimeStartup>()
            .Build()
            .Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}

为什么这么复杂?

  • 脚手架
    • 第一个脚手架(添加第一个控制器+ Views + Entity Framework)始终读取Startup类以将MyDbContext注册为服务。 (目前)没有办法指向另一个班级!如果你尝试,你会得到:
        

      Scaffolding无法编辑Startup类以注册新的Context   使用依赖注入。确保有一个Startup类和一个   其中包含ConfigureServices方法和Configuration属性。

    • 除了脚手架之外,还调用BuildWebHost方法。所以你需要在这里使用Startup。否则你会得到这个误导性的消息:
        

      没有为此对象定义无参数构造函数。

  • 迁移仅使用BuildWebHost方法访问启动类(与scaffolding相同)。

结论:

因此,如果您不想在每次添加新Controller或添加/删除迁移时调用迁移和种子,则必须提供精简Startup类并将(运行时)内容放在其他位置! / p>

您可以在设计时和运行时启动时创建一个重用ConfigureServices()方法的基类。 (请记住,脚手架在修改Startup的基本类型时总是会失败。但据我所知,只有通过将MyDbContext注册为服务才能实现。这应该是可管理的。)