来自分段的无缝EF迁移>使用架构更改生成

时间:2016-07-30 01:48:31

标签: entity-framework azure ef-code-first azure-sql-database

我有一个简单的网络应用程序。它由带有暂存和生产插槽的Azure Web App组成。如果没有要考虑的数据库迁移,我可以通过以下方式轻松实现无缝更新:

  1. 将应用程序部署到暂存
  2. 交换分段<>生产槽
  3. 当我需要进行数据库迁移时,这会变得更加棘手。现在我所做的是:

    1. 将应用程序部署到暂存
    2. 部署准备就绪后,将update-database运行到Prod(无临时数据库)
    3. 交换分段<>生产槽
    4. 这意味着我仍然有效地停机,因为2 + 3不会同时发生,这意味着在几秒钟内,我的用户将会因为“数据库模式发生变化”而遇到不完美的行为。

      这里最简单的解决方案是什么?我想我可能也需要启动一个临时数据库,但是我不得不担心复制和连接字符串管理会增加一些开销。

1 个答案:

答案 0 :(得分:9)

将我们的解决方案转移到持续交付模式并希望避免停机时,我们遇到了同样的困境。

您需要将EF配置为在开发环境中运行 Code-First ,并在生产中运行 Database-First

这使您可以将更改分为三个阶段:

阶段1.数据库迁移

在此阶段,您将使用EF的migrate.exe实用程序(或者只是手动编写脚本)来针对实时数据库运行最新的迁移。应用迁移后,生产中的网站仍然保持正常运行(因为它配置为数据库优先)。

重要的一点是您需要确保您在此阶段的迁移是添加,因为它会更改let表示的表或列这将导致实时网站崩溃。它可能看起来很可怕,但如果您的项目足够成熟,您很快就会意识到您的架构的大多数更改要么完全是附加的,要么可以分为两个阶段。 (见第3阶段)

阶段2.更新生产网站

在这个阶段做正常的分期 - >生产网站部署。

阶段3.数据库迁移(第2部分)

在极少数例如您重命名了数据库表或列的情况下,您需要考虑将其分为两个步骤:

  • 添加新列(在第1部分中完成)
  • 删除旧列并迁移数据(在第2部分中完成)。

附录

EF数据库 - 仅限于生产

Startup.csGlobal.asax.cs

#if DEBUG
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<AppDatabase, Migrations.Migrations.Configuration>());
#else
    Database.SetInitializer(new RequireDatabaseToBeUpToDate<AppDatabase, Migrations.Migrations.Configuration>());
#endif

这正是它在锡上所说的:

  • 在本地:将其数据库迁移到最新迁移。
  • 在生产中:确保数据库迁移对其正在使用的模型程序集 NOT AHEAD 。 - 这是一项安全措施,即使我们在数据库之前意外地部署了网页,它也会阻止网站启动。
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