在将解决方案迁移到持续交付模型时,我们也面临同样的困境,并且希望避免停机。
您需要配置您的 EF 以在开发环境中运行 Code-First 并在生产环境中运行 Database-First。
这使得您可以将更改推送到三个阶段:
第一阶段。数据库迁移
在此阶段,您将使用 EF 的 migrate.exe 实用程序(或简单地事先编写脚本)针对实时数据库运行最新迁移。应用迁移后,您的网站在生产中仍然可以正常运行,因为没有发生任何事情(因为它被配置为数据库优先)。
重要的一点是你需要确保你在这个阶段的迁移是additive的,因为它会改变一个比方说的表或列这将导致现场网站崩溃。它可能看起来很吓人,但是如果您的项目足够成熟,您很快就会意识到对架构的大多数更改要么完全是附加的,要么可以分为两个阶段。 (见第 3 阶段)
第 2 阶段。更新生产网站
在这个阶段进行正常的Staging --> Production网站部署。
第 3 阶段。数据库迁移(第 2 部分)
在极少数情况下,例如重命名数据库表或列,您需要考虑将其分为两个步骤:
- 添加新列(在第 1 部分中完成)
- 删除旧列并迁移数据(在第 2 部分中完成)。
附录
EF Database-First 仅在生产中
在您的Startup.cs 或Global.asax.cs:
#if DEBUG
Database.SetInitializer(new MigrateDatabaseToLatestVersion<AppDatabase, Migrations.Migrations.Configuration>());
#else
Database.SetInitializer(new RequireDatabaseToBeUpToDate<AppDatabase, Migrations.Migrations.Configuration>());
#endif
这正是它在锡上所说的:
-
在本地:将其数据库迁移到最新迁移。
-
生产中:确保数据库迁移不领先它正在使用的模型程序集。 -- 这是一项安全措施,确保即使我们在数据库之前意外部署了网络,它也能阻止网站启动。
public class RequireDatabaseToBeUpToDate<TContext, TMigrationsConfiguration> : IDatabaseInitializer<TContext>
where TContext : DbContext
where TMigrationsConfiguration : DbMigrationsConfiguration, new()
{
public void InitializeDatabase(TContext context)
{
var migrator = new DbMigrator(new TMigrationsConfiguration());
var migrations = migrator.GetPendingMigrations().ToList();
if (migrations.Any())
{
var message = "There are pending migrations that must be applied (via a script or using migrate.exe) before the application is started.\r\n" +
$"Pending migrations:\r\n{string.Join("\r\n", migrations)}";
throw new MigrationsPendingException(message);
}
}
}
针对实时数据库运行迁移
$migrate = "<path>\migrate.exe"
$migrateConfig = "<path>\migrate.exe.config"
$connectionString = <your-live-connection-string>
& $migrate <your-project-migration-assembly> /startupConfigurationFile=$migrateConfig <your-migration-configuration-type-name> /connectionString=$connectionString /connectionProviderName=System.Data.SqlClient /verbose