建立自动迁移和播种而不损坏实体框架工具链
不幸的是Entity Framwork Core不再支持IDatabaseInitializer
s:所以没有DropCreateDatabaseAlways.Seed()
和DropCreateDatabaseIfModelChanges.Seed()
。 :-(建立自动迁移和播种而不损坏实体框架工具链
所以人们在那里写了很多东西:。
- 创建数据库,如果不存在
- 数据库迁移到最新的版本
- 应用种子的数据,如果#1 (数据库为空)与
DbContext
具体实例的帮助。
我在Startup.Configure
0结束想出了以下行在那里我得到IApplicationBuilder app
和IHostingEnvironment 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()
致电我的Startup
和Startup.ConfigureServices()
以及Startup.Configure()
(即使不需要:https://github.com/aspnet/EntityFrameworkCore/issues/9076)。即使我打电话Remove-Migration
狗屎糟糕的打扇:Remove-Migration
→Startup.Configure()
→迁移&种子(数据库是在最新的迁移=无迁移删除)→错误:
The migration '20170914084432_MyMigration' has already been applied to the database. Revert it and try again. If the migration has been applied to other databases, consider reverting its changes using a new migration.
简单的说,我怎么能运行我的移植&种子从工具链分别告诉我的工具链手Startup.Configure()
?
请记住:我不喜欢用IDesignTimeDbContextFactory
因为......
- 我不明白的依赖注入,所以没有
IConfiguration
实例来检索连接字符串。 - 我不想保留冗余连接字符串。这是错误!
- 并且自己使用
ConfigurationBuilder
也是多余的(Get ConnectionString from appsettings.json instead of being hardcoded in .NET Core 2.0 App)。特别是在EF Core 2.0中,由于您总是需要模拟WebHost.CreateDefaultBuilder()
,因此它非常麻烦且错误。 - 即使有
IDesignTimeDbContextFactory
到位Program.BuildWebHost()
和最后Startup.ConfigureServices()
仍然被调用(并且https://github.com/aspnet/EntityFrameworkCore/issues/9076#issuecomment-313278753是一个糟糕的解决方法!)。
经过数小时的猜测和失败,我放弃了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();
}
为什么这么复杂?
- 脚手架
- 第一脚手架(添加第一控制器+浏览+实体框架)总是读取
Startup
类来注册MyDbContext
作为服务。目前没有办法指向另一个班级!如果你尝试,你会得到:Scaffolding failed to edit Startup class to register the new Context using Dependency Injection. Make sure there is a Startup class and a ConfigureServices method and Configuration property in it.
- 除了脚手架也调用
BuildWebHost
方法。所以你也需要在这里使用Startup
。否则,你得到这个消息误导:No parameterless constructor defined for this object.
- 第一脚手架(添加第一控制器+浏览+实体框架)总是读取
- 迁移仅使用
BuildWebHost
方法去启动类(同脚手架)。
结论:
所以,如果你不想打电话给你的迁移和播种每次你添加一个新的控制器或添加/删除迁移,你必须提供一个瘦Startup
类,并把(运行时)的东西在别的地方!
您可以在设计时和运行时创建时创建一个基类,重用ConfigureServices()
方法。 (请记住脚手架在修改基本类型Startup
时总是会失败,但据我所知,它只会通过注册MyDbContext
作为服务而发生,而且应该可以管理。)