我有一个简单的网络应用程序。它由带有暂存和生产插槽的Azure Web App组成。如果没有要考虑的数据库迁移,我可以通过以下方式轻松实现无缝更新:
当我需要进行数据库迁移时,这会变得更加棘手。现在我所做的是:
这意味着我仍然有效地停机,因为2 + 3不会同时发生,这意味着在几秒钟内,我的用户将会因为“数据库模式发生变化”而遇到不完美的行为。
这里最简单的解决方案是什么?我想我可能也需要启动一个临时数据库,但是我不得不担心复制和连接字符串管理会增加一些开销。
答案 0 :(得分:9)
将我们的解决方案转移到持续交付模式并希望避免停机时,我们遇到了同样的困境。
您需要将EF配置为在开发环境中运行 Code-First ,并在生产中运行 Database-First 。
这使您可以将更改分为三个阶段:
在此阶段,您将使用EF的migrate.exe
实用程序(或者只是手动编写脚本)来针对实时数据库运行最新的迁移。应用迁移后,生产中的网站仍然保持正常运行(因为它配置为数据库优先)。
重要的一点是您需要确保您在此阶段的迁移是添加,因为它会更改let表示的表或列这将导致实时网站崩溃。它可能看起来很可怕,但如果您的项目足够成熟,您很快就会意识到您的架构的大多数更改要么完全是附加的,要么可以分为两个阶段。 (见第3阶段)
在这个阶段做正常的分期 - >生产网站部署。
在极少数例如您重命名了数据库表或列的情况下,您需要考虑将其分为两个步骤:
在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