将实体框架4.1数据库迁移到EF5进行升级,为新安装创建新数据库

时间:2013-02-09 21:44:46

标签: c# .net entity-framework

我目前正在开发具有版本1用户的现有代码库的应用程序的第2版,但我还需要将新版本推广到新用户(即干净安装)。版本1使用Entity Framework 4.1。版本2使用实体框架5。

我的问题是我需要能够将现有版本1用户升级到版本2并将其数据库迁移到新版本的架构。新模式添加了许多新表,使一些现有表保持不变并删除其他表。

我在旅途中发现EF4.1不包含_MigrationHistory表。所以我回到原来的第1版代码,将其升级到EF5并按如下方式运行初始迁移:

Add-Migration Initial -IgnoreChanges

这很适合让原始版本1(EF4.1)数据库准备好进行迁移(即添加_MigrationHistory表)。然后我将其移植到我的第2版代码并运行:

Update-Database

创建_MigrationHistory表,然后运行:

Add-Migration Version2

可以生成数据库到版本2的良好迁移。

如果数据库已经存在于版本1架构或版本2架构(在后一种情况下不应用迁移),那么这种方法非常有效,因为我正在使用以下初始化器:

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

但是,如果数据库不存在,则Initial迁移成功运行,但Version2迁移失败,因为某些迁移步骤会删除表,索引和外键,这显然不会t存在于空数据库中。

所以我完全不知所措 - 如何将现有版本1用户迁移到版本2(并保留其数据),还支持需要从头开始创建数据库的新安装?

我已经看到很多关于创建和运行SQL脚本进行迁移的想法,但我真的需要在启动我的应用程序时自动完成。最终用户实际上只需要运行MSI文件即可升级。

更新:以下是w.brian建议的解决方案(抱歉,我还无法进行投票):

string connectionString = ConfigurationManager.ConnectionStrings["DbContext"].ConnectionString;
if (Database.Exists(connectionString))
{
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbContext, Migrations.Configuration>());
}
else
{
    Database.SetInitializer(new DefaultDataInitialiser());
}

UPDATE2 :上述内容似乎第一次通过新的创建工作。但是,下一次运行会通过Database.Exists()检查并尝试迁移数据库。但是,由于_MigrationHistory表中只有一个条目(由new / clean安装生成),并且迁移有两个条目(一个用于EF4.1迁移;一个用于新模式),因此迁移逻辑从头开始,并尝试应用每次迁移。

这会失败,因为它尝试创建已存在于数据库中的表 - 它是作为干净安装的一部分创建的!

所以关键在于,这种方法会影响迁移逻辑。

UPDATE3 :所以我想我已经找到了如何创建初始数据库并允许后续运行仅应用迁移。从上面看,如果数据库已经存在,请继续使用迁移代码。

如果数据库尚不存在,请使用DefaultDataInitialiser并在Seed()方法中执行以下操作:

context.Database.ExecuteSqlCommand(@"DELETE FROM [__MigrationHistory]");

byte[] version1Model = ConvertHexStringToByteArray("1F8B...");
context.Database.ExecuteSqlCommand(@"INSERT INTO [__MigrationHistory]
                                        ([MigrationId]
                                        ,[Model]
                                        ,[ProductVersion])
                                    VALUES
                                        ('201302082120145_Initial'
                                        ,{0}
                                        ,'5.0.0.net40')", new object[] { version1Model });

byte[] version2Model = ConvertHexStringToByteArray("1F8B...");
context.Database.ExecuteSqlCommand(@"INSERT INTO [__MigrationHistory]
                                        ([MigrationId]
                                        ,[Model]
                                        ,[ProductVersion])
                                    VALUES
                                        ('201302082200350_Version-2'
                                        ,{0}
                                        ,'5.0.0.net40')", version2Model);

这使得新数据库从迁移逻辑的角度“完全迁移”。下次运行应用程序时,数据库存在且MigrateDatabaseToLatestVersion魔法运行,发现数据库处于最新版本(或将来升级到下一次迁移)并且很高兴。

不幸的是,将来需要将每个新的迁移添加到此Seed()方法中,以便从头开始创建数据库。

我从哪里获得用于模型的十六进制字符串?我是从迁移版本的数据库中从SQL Server Management Studio复制的。

1 个答案:

答案 0 :(得分:1)

我只会在升级时使用MigrateDatabaseToLatestVersion初始化程序,而不是在新安装时使用。这将要求您直接查询SQL Server以查看数据库是否存在,但我认为这不应该太困难,因为您可以访问连接字符串。