从分期进行无缝EF迁移>生产与模式变化 [英] Seamless EF Migrations from Staging > Production with Schema Change

查看:182
本文介绍了从分期进行无缝EF迁移>生产与模式变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的网络应用程序。它包括一个具有分段和生产插槽的Azure Web App。当没有需要考虑的DB迁移时,可以通过以下方式轻松实现无缝更新:


  1. 将App部署到分段

  2. 交换分段<>生产插槽

当我有一个DB迁移来处理时,这会变得更加棘手。现在我所做的是:


  1. 将应用程序部署到分段

  2. 部署准备就绪后,运行更新数据库到Prod(无分段数据库)

  3. 交换分段<>生产插槽

这意味着我仍然有效地停机,因为2 + 3不会同时发生,这意味着在几秒钟之内,我的用户会遇到DB模式已经改变的不完美的行为。



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

解决方案

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



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



这样可以推送更改生活在三个阶段:



阶段1.数据库迁移



在这个阶段,您将使用EF migrate.exe 实用程序(或者简单地在手上编写脚本),以便根据实时数据库运行最新的迁移。迁移后,您的网站在生产中仍然保持功能,因为没有发生任何事情(因为它被配置为首先是数据库)。



重要的一点是,您需要确保在此阶段的迁移是添加,在某种意义上它会改变一个让我们说会使现场网站崩溃的表或列。它可能看起来很可怕,但如果您的项目已经足够成熟,您很快将意识到,您的模式的大部分更改是完全添加的,或者可以分为两个阶段。 (见阶段3)



阶段2.更新制作网站



在这个阶段,你的普通



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



在这样一些罕见的情况下,例如数据库表或列被重命名,您将需要考虑将其分为两个步骤:




  • 添加新列(在第1部分中完成)

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






附录



EF数据库 - 仅在生产中首先



在您的 Startup.cs Global.asax.cs

  #if DEBUG 
Database.SetInitializer(新的MigrateDatabaseToLatestVersion&AppDatabase,Migrations.Migrations.Configuration>());
#else
Database.SetInitializer(新的RequireDatabaseToBeUpToDate&AppDatabase,Migrations.Migrations.Configuration>());
#endif

这完全符合锡上所说的:




  • 本地:将数据库迁移到最新的迁移。

  • 确保数据库迁移是正在使用的模型程序集的 NOT AHEAD 。 - 这是一个安全措施,确保即使我们在数据库之前意外部署了网站,也阻止了网站的启动。






  public class RequireDatabaseToBeUpToDate< TContext,TMigrationsConfiguration> :IDatabaseInitializer< TContext> 
其中TContext:DbContext
其中TMigrationsConfiguration:DbMigrationsConfiguration,new()
{
public void InitializeDatabase(TContext context)
{
var migrator = new DbMigrator (新的TMigrationsConfiguration());
var migrations = migrator.GetPendingMigrations()。ToList();
if(migrations.Any())
{
var message =在启动应用程序之前,有待处理的迁移必须应用(通过脚本或使用migrate.exe)。 \\\\
+
$待迁移:\r\\\
{string.Join(\r\\\
,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


I have a simple web app. It consists of an Azure Web App with Staging and Production slots. When there are no DB migrations to consider, I can easily achieve a seamless update by:

  1. Deploy App to Staging
  2. Swap Staging <> Production Slots

This gets trickier when I have a DB migration to handle. Right now what I do is:

  1. Deploy App to Staging
  2. When deployment is ready, run update-database to Prod (no staging database)
  3. Swap Staging <> Production Slots

This means that I still effectively have downtime as 2 + 3 don't happen simultaneously, which means that for some seconds, my users will experience imperfect behavior as the 'DB schema has changed'.

What is the simplest solution here? I'm thinking I may have to spin up a staging database too, but then I have to worry about replication and connection string management which adds a bit of overhead.

解决方案

We had the same dilemma when moving our solution to continuous delivery model and wanted to avoid downtime.

You need to configure your EF to run Code-First on development environment and Database-First in production.

This makes it possible to push your changes to live in three stages:

Stage 1. Database Migrations

At this stage, you will use EF's migrate.exe utility (or simply script them before hand) to run your latest migrations against the live database. After migrations are applied your website in production still keeps functioning as nothing has happened (because it's configured to be database-first).

The important bit is that you need to make sure your migrations at this stage are additive, in the sense that it would'd change a let's say table or column that will cause the live site to crash. It may look scary, but if your project is mature enough, you soon will realise that most of changes to your schema are either completely additive or can be broken down into two stages. (see stage 3)

Stage 2. Update production website

At this stage do your normal Staging --> Production website deployment.

Stage 3. Database Migrations (part 2)

In those rare cases where you had for example a database table or column renamed, you will need to consider breaking it into two steps of:

  • Add a new column (done in part 1)
  • Remove old column and migrate data (done in part 2).

Appendices

EF Database-First only in production

In your Startup.cs or Global.asax.cs:

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

This does exactly what it says on the tin:

  • On Local: Migrates it's database to latest migration.
  • In Production: Ensures that the database migrations is NOT AHEAD of the model assembly it is using. -- this is a safety measure making sure even if we ever accidentally deployed web before database, it stops the site from firing up.

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);
        }
    }
}

Running migrations against live database

$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

这篇关于从分期进行无缝EF迁移&gt;生产与模式变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆