在生产中使用实体框架(代码优先)迁移

Posted

技术标签:

【中文标题】在生产中使用实体框架(代码优先)迁移【英文标题】:Using Entity Framework (code first) migrations in production 【发布时间】:2012-06-06 14:30:12 【问题描述】:

我只是想为我们的项目使用 EF 迁移,特别是在发布之间执行生产中的架构更改。

我看到提到有一个 API 可以使用 DbMigration 类在运行时执行这些迁移,但我找不到任何具体示例。

理想情况下,我希望为每个数据库更改创建一个 DbMigration 文件,并在应用程序从当前版本到最新版本启动时自动应用这些更改。

【问题讨论】:

Entity framework 4.3 run migrations at application start 的可能重复项 【参考方案1】:

有一个数据库初始化器,您可以使用它来实现在启动时迁移到最新版本(或者更好的是,dbinitializer 将在第一次访问数据库时启动),MigrateDatabaseToLatestVersion,您可以这样使用它:

Database.SetInitializer<ObjectContext>(
    new MigrateDatabaseToLatestVersion<ObjectContext, Configuration>());

关于每次迁移只有一个文件,如果您启用自动迁移,您将在项目根目录的 Migrations 文件夹(默认情况下)中找到它们。

相关信息及示例,请点击此处:http://weblogs.asp.net/fredriknormen/archive/2012/02/15/using-entity-framework-4-3-database-migration-for-any-project.aspx

【讨论】:

这段代码要添加到哪里?这可以包含在条件语句中以检查 web.config 文件中的应用程序设置吗?以便在开发过程中可以跳过此代码?那么 web.config 转换会在发布发布版本时启用它吗? 如果您需要有条件地为配置属性设置初始化程序,那么更好的方法是使用 EF4.3 的功能。参考这篇文章msdn.microsoft.com/en-US/data/jj556606(“Database Initializer”部分),将它与转换结合使用,你就设置好了 更多信息在这里:msdn.microsoft.com/en-us/data/jj591621.aspx#initializer 对于那些对自动迁移和数据库模式更新持谨慎态度,并认为手动编辑脚本更安全的人......验证你有看在上帝的份上,先备份并测试一下!! 我在更新this question时扩展了主题,欢迎同行评审 此解决方案意味着应用有权更改架构。我认为这在应用程序仅限于数据操作的 prod 环境中不太可能。我想知道是否可以使用 dotnet CLI(从管理员帐户或通过提供凭据)从编译的 DLL 运行迁移【参考方案2】:

这也有效:

var configuration = new MyDbContextConfiguration();
configuration.TargetDatabase = new DbConnectionInfo(
    database.ConnectionString, database.ProviderName);

var migrator = new DbMigrator(configuration);
migrator.Update();

您也可以调用:

migrator.GetPendingMigrations();

获取需要应用的迁移列表。

【讨论】:

这里的变量database是什么? 在这种情况下只是一个具有 ConnectionString 和 ProviderName 属性的 DTO。它不是框架的一部分。 如果我使用这个方法,我应该在我的 dbContext create 上使用什么初始化器? 在你的 DbContext 构造函数中只做:Database.SetInitializer(null); 这对我有用,甚至删除了 new DbConnectionInfo 部分。谢谢!【参考方案3】:

我想控制哪些迁移在代码中显式运行,经过大量搜索后,我设法开发了以下技术,而无需 DbConfiguration 类或启用自动迁移:

public static void RunMigration(this DbContext context, DbMigration migration)
            
    var prop = migration.GetType().GetProperty("Operations", BindingFlags.NonPublic | BindingFlags.Instance);
    if (prop != null)
    
        IEnumerable<MigrationOperation> operations = prop.GetValue(migration) as IEnumerable<MigrationOperation>;
        var generator = new SqlServerMigrationSqlGenerator();
        var statements = generator.Generate(operations, "2008");
        foreach (MigrationStatement item in statements)
            context.Database.ExecuteSqlCommand(item.Sql);
    

如果我们有这样的迁移:

public class CreateIndexOnContactCodeMigration : DbMigration

    public override void Up()
    
        this.CreateIndex("Contacts", "Code");
    

    public override void Down()
    
        base.Down();
        this.DropIndex("Contacts", "Code");
    

我们会这样使用它:

using (var dbCrm = new CrmDbContext(connectionString))

    var migration = new CreateIndexOnContactCodeMigration();
    migration.Up();                
    dbCrm.RunMigration(migration);

问候。

【讨论】:

【参考方案4】:

由于您没有指定您使用的是哪个 Visual Studio 版本或数据库,我将在此处添加一个答案,说明在 VS2015 中使用 Microsoft 的 SQL Server,现在使用“发布”工具非常容易。

您无需为您所说的 API 操心。只需在本地完成工作、更改模型、应用迁移等,然后当您想要推送到发布/测试服务器时,请使用发布工具。

您可以选择在首次启动应用程序时将您在本地进行的任何迁移应用到远程服务器。

一旦您完成了所有迁移并在本地完成所有操作(可能在您的开发环境中),然后您发布(右键单击项目,单击“发布...”勾选“执行代码优先迁移(在应用程序启动时运行) "“设置”选项卡下的复选框,然后它将在第一次访问应用程序时应用迁移(因此第一次会有短暂的延迟)。

指南: https://msdn.microsoft.com/en-us/library/dd465337(v=vs.110).aspx

我学到了所有这些,因为我必须对 Windows 2012 服务器执行此操作: http://www.sherweb.com/blog/how-to-install-webdeploy-on-windows-server-2012/

祝你好运!

【讨论】:

只是一个扩展评论,因为我现在年纪大了,也更聪明了。通常你不想在生产服务器上自动执行迁移。理想情况下,您生成一个 SQL 脚本来进行迁移,验证它是否符合您的要求,然后在发布/部署您的应用程序时在生产数据库上运行该脚本。这是做这件事的“标准”方式。 这在发布到File System时不可用【参考方案5】:

添加到所有已发布的答案。实体框架使用表:dbo.__MigrationHistory 来跟踪已应用于数据库的所有迁移,以避免运行迁移,例如:插入数据或更改数据库架构。

如果您希望运行脚本,例如运行添加数据或更改数据库架构,您可以使用包管理器控制台创建一个空迁移并通过新添加的迁移运行脚本。确保使用初始化程序来防止 EF 在每次运行时删除和重新创建数据库。

     public override void Up()
    
        string directoryToSearchScripts = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\..\\"));

        string scriptFilePath = Directory.GetFiles(directoryToSearchScripts, "dummy-script.sql", SearchOption.AllDirectories).FirstOrDefault();
        if (!string.IsNullOrEmpty(scriptFilePath))
        
            string fundsSqlScript = File.ReadAllText(scriptFilePath);
            Sql(fundsSqlScript);
        
    

    public override void Down()
    
    

当您发布应用程序并选中“执行代码优先迁移”选项时,EF 将运行尚未应用到数据库的迁移。

【讨论】:

以上是关于在生产中使用实体框架(代码优先)迁移的主要内容,如果未能解决你的问题,请参考以下文章

实体框架 - 迁移 - 代码优先 - 每次迁移播种

调试代码优先的实体框架迁移代码

实体框架代码优先迁移 - 我可以针对以前的迁移

使用实体框架在代码优先迁移中有条件地插入数据

实体框架代码优先:迁移失败并更新数据库,强制不必要的(?)添加迁移

无法在 .NET 中的实体框架代码优先方法中迁移 AspNetUser 实体