ef 代码优先 - 实体框架代码优先迁移,运行迁移,可选择升级到最新更改



我们正在运行启用了代码优先迁移实体框架 5。使用数据库初始值设定项运行:MigrateToLatestVersion

我们有几个客户在最新的稳定分支上运行。当我们在主干/主干中开发新代码时,我们有时需要连接到在分支代码 fx 上运行的客户数据库。调试某种数据错误。

如果有人忘记切换到客户正在运行的分支,这可能是"危险的",因为迁移将升级客户数据库以适应该人正在运行的任何代码。

一种解决方案是运行另一个不会迁移到最新版本的初始值设定项。但是,当我们向新客户部署新系统或新人加入团队并且需要启动并运行时,这将意味着更多的工作。

我们正在考虑通过在 app.config 中设置一个 bool 来设置代码是否应该"迁移到最新版本",然后始终将其设置为 false 以进行开发,然后在部署到客户时对其进行转换来解决此问题。

这样,我们就可以获得仍然让数据库自动更新到最新版本的好处,但不会有开发人员意外连接到旧版本代码系统以及迁移破坏该数据库的危险。

所以现在我们有了这个,我们基本上需要检查这个:

(简化代码)

if(Config.MigrateToLatestVersion || !databaseExists) 
{
  var initializer = new MigrateToLatestVersion<MyContext,MigrationConfiguration>();
  Database.SetInitializer(initializer);
  using(var context = new MyContext())
  {
    context.Database.Initialize(true)
  }
}

我的问题将是关于如何在不运行迁移的情况下检查数据库是否存在,但我发现您可以这样做:

Database.SetInitializer<MyContext>(null);
var context = new MyContext();
var databaseExists = context.Database.Exists();

但是,如果我仅在数据库不存在或从包管理器控制台手动运行 Update-Database 时才运行 MigrateToLatestVersion 初始值设定项。

有两个问题,首先:我不再收到一个异常,说我的模型是否与数据库不同,我仍然喜欢。第二:它不运行位于我的迁移配置中的种子方法,我可能仍然想运行该方法。

关于我如何仍然可以运行迁移初始值设定项以获得所有好处,但仍然有一些东西可以防止有人意外破坏我们的生产环境,有什么建议吗?

所以我

的解决方案是制作一个名为MigrateDatabaseToLatestIfLocal的新DatabaseInitializer

查看 MigrateDatabaseToLatestVersion 初始值设定项的工作原理,我做了一些非常相似的事情,不同之处在于检查数据库是否存在以及我们是在本地运行还是远程运行(借助配置转换来确定这一点。远程系统的数据源在配置文件中进行了转换。

public class MigrateDatabaseToLatestIfLocal<TContext, TMigrationsConfiguration> : IDatabaseInitializer<TContext>
        where TContext : DbContext
        where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new()
    {
        private DbMigrationsConfiguration _config;
        public MigrateDatabaseToLatestIfLocal()
        {
            this._config = (DbMigrationsConfiguration)Activator.CreateInstance<TMigrationsConfiguration>();
        }
        public MigrateDatabaseToLatestIfLocal(string connectionStringName)
        {
          MigrateDatabaseToLatestIfLocal<TContext, TMigrationsConfiguration> databaseToLatestVersion = this;
          var instance = Activator.CreateInstance<TMigrationsConfiguration>();
          instance.TargetDatabase = new DbConnectionInfo(connectionStringName);
            databaseToLatestVersion._config = instance;
        }
        public void InitializeDatabase(TContext context)
        {
            var databaseExists = context.Database.Exists();
            var migrator = new DbMigrator(this._config);
            var pendingMigrations = migrator.GetPendingMigrations().OrderByDescending(s => s);
            var localMigrations = migrator.GetLocalMigrations().OrderByDescending(s => s);
            var dbMigrations = migrator.GetDatabaseMigrations().OrderByDescending(s => s);

            var isRemoteConnection = FunctionToFindOutIfWeAreRemote(); //here we check the config file to see if the datasource is a certain IP, this differentiates locally and remotely because of config tranformation.
            if (isRemoteConnection && databaseExists)
            {
                if (pendingMigrations.Any())
                {
                    throw new MigrationsException("You are not allowed to automatically update the database remotely.")
                }
                if (localMigrations.First() != dbMigrations.First())
                {
                    throw new MigrationsException("Migrations in code and database dont match, please make sure you are running the code supported by the remote system. ");
                }
            }
            else
            {
                //we are local, fine update the db and run seeding.
                //we are remote and the db does not exist, fine update and run seed.
                migrator.Update();
            }
        }
    }

这可能是一个非常特殊的情况,但对我来说,它在运行代码优先迁移时提供了一些安全性,确保您不会意外地随机迁移实时环境。

最新更新