如何使用新生成的数据库添加新的代码优先迁移?

Jez*_*Jez 2 sql-server data-migration entity-framework ef-code-first ef-migrations

我已经在我的实体框架项目上启用了代码优先迁移,并添加了一些迁移,这些迁移执行重命名表等操作.但是,我现在已经删除了数据库并导致实体框架根据我的最新数据模型生成一个全新的数据库.如果我尝试运行:

PM> Add-Migration TestMigration
Run Code Online (Sandbox Code Playgroud)

...它告诉我,我需要先应用现有的迁移.所以我跑:

PM> Update-Database
Run Code Online (Sandbox Code Playgroud)

...但问题是它正在尝试更新不需要更新的数据库; 它已经基于最新的数据模型.因此,当我尝试重命名现在不存在的表时,我收到错误.

我是否可以通过某种方式向数据迁移指出我的数据库是最新的并且不需要在其上运行任何迁移?我该怎么办?

Jez*_*Jez 9

我找到了一种方法来表明我的数据库是最新的,并且(不出所料)基于修改__MigrationHistory表,代码优先迁移用于确定在运行时应用于数据库的迁移Update-Database.

顺便说一下,在研究这个答案时,我遇到了一个非常好的代码优先迁移命令参考,可以在以下网址找到:http://dotnet.dzone.com/articles/ef-migrations-command

当EF自动从头创建数据库时,它将始终将一个条目放入__MigrationHistory表中,该条目将具有MigrationId (currentDateTime)_InitialCreate.这表示EF刚刚执行的数据库的初始创建.但是,您的迁移历史记录不会以该MigrationId开头,因为您将从其他内容开始.

为了"欺骗"代码优先迁移,认为您正在进行最新迁移,您需要从新创建的数据库(currentDateTime)_InitialCreate__MigrationHistory表中删除该条目,并插入如果您仍然拥有旧数据库的那些条目已经将迁移应用于它.

因此,首先从新生成的DB __MigrationHistory表中删除所有内容.然后,进入包管理器控制台并运行:

PM> Update-Database -Script
Run Code Online (Sandbox Code Playgroud)

从生成的SQL脚本中,拉出所有以下行开头的行:

INSERT INTO [__MigrationHistory]...
Run Code Online (Sandbox Code Playgroud)

然后,INSERT在新创建的数据库的上下文中运行这些语句.检查__MigrationHistory表中是否存在这些行.下次运行时:

PM> Update-Database
Run Code Online (Sandbox Code Playgroud)

...你应该收到一条消息"没有待定的基于代码的迁移." 恭喜 - 您已经愚弄了代码优先迁移,认为您现在正在进行最新迁移,并且您可以继续从此处继续添加新迁移.

我认为应该有一些自动化的方法来构建到EF代码 - 首先,但是...也许他们应该添加如下内容:

PM> Update-Database -MigrationsTableOnly
Run Code Online (Sandbox Code Playgroud)

...它会破坏迁移表中的现有条目,只需将新条目插入到项目中定义的每个迁移的迁移历史记录中,但实际上不会尝试运行迁移.呃,好吧.

更新
我已经找到了一种使用自定义初始化程序的Seed方法很好地自动化的方法.基本上,Seed方法会在创建数据库时删除现有的迁移历史记录数据,并插入迁移历史记录.在我的数据库上下文构造函数中,我像这样注册自定义初始化程序:

public class MyDatabaseContext : DbContext {
    public MyDatabaseContext() : base() {
        Database.SetInitializer(new MyDatabaseContextMigrationHistoryInitializer());
    }
Run Code Online (Sandbox Code Playgroud)

自定义初始化程序本身如下所示:

/// <summary>
/// This initializer clears the __MigrationHistory table contents created by EF code-first when it first
/// generates the database, and inserts all the migration history entries for migrations that have been
/// created in this project, indicating to EF code-first data migrations that the database is
/// "up-to-date" and that no migrations need to be run when "Update-Database" is run, because we're
/// already at the latest schema by virtue of the fact that the database has just been created from
/// scratch using the latest schema.
/// 
/// The Seed method needs to be updated each time a new migration is added with "Add-Migration".  In
/// the package manager console, run "Update-Database -Script", and in the SQL script which is generated,
/// find the INSERT statement that inserts the row for that new migration into the __MigrationHistory
/// table.  Add that INSERT statement as a new "ExecuteSqlCommand" to the end of the Seed method.
/// </summary>
public class MyDatabaseContextMigrationHistoryInitializer : CreateDatabaseIfNotExists<MyDatabaseContext> {
    /// <summary>
    /// Sets up this context's migration history with the entries for all migrations that have been created in this project.
    /// </summary>
    /// <param name="context">The context of the database in which the seed code is to be executed.</param>
    protected override void Seed(MyDatabaseContext context) {
        // Delete existing content from migration history table, and insert our project's migrations
        context.Database.ExecuteSqlCommand("DELETE FROM __MigrationHistory");
        context.Database.ExecuteSqlCommand("INSERT INTO __MigrationHistory (MigrationId, Model, ProductVersion) VALUES ('201210091606260_InitialCreate', 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E074A..., '5.0.0.net40')");
        context.Database.ExecuteSqlCommand("INSERT INTO __MigrationHistory (MigrationId, Model, ProductVersion) VALUES ('201210102218467_MakeConceptUserIdNullable', 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4..., '5.0.0.net40')");
        context.Database.ExecuteSqlCommand("INSERT INTO __MigrationHistory (MigrationId, Model, ProductVersion) VALUES ('201210231418163_ChangeDateTimesToDateTimeOffsets', 0x1F8B0800000000000400ECBD07601C499625262F6D..., '5.0.0.net40')");
        context.Database.ExecuteSqlCommand("INSERT INTO __MigrationHistory (MigrationId, Model, ProductVersion) VALUES ('201210251833252_AddConfigSettings', 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E..., '5.0.0.net40')");
        context.Database.ExecuteSqlCommand("INSERT INTO __MigrationHistory (MigrationId, Model, ProductVersion) VALUES ('201210260822485_RenamingOfSomeEntities', 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF5..., '5.0.0.net40')");
    }
}
Run Code Online (Sandbox Code Playgroud)