如何使用新生成的数据库添加新的代码优先迁移? [英] How to add a new code-first migration with a newly-generated database?

本文介绍了如何使用新生成的数据库添加新的代码优先迁移?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've enabled code-first migrations on my entity framework project, and have added several migrations which do things like rename tables. However, I have now deleted the database and caused entity framework to generate a brand new database based on my latest data model. If I try to run:

PM> Add-Migration TestMigration

...它告诉我,我需要首先应用现有迁移。所以我运行:

... it tells me that I need to apply the existing migrations first. So I run:

PM> Update-Database

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

... but the trouble is that it's trying to update a database that doesn't need updating; it's already based on the latest data model. So I get an error when it tries to rename a table that now doesn't exist.

是否可以通过某种方式向数据迁移表明我的数据库已正常运行-到目前为止,不需要任何迁移吗?我应该怎么办?

Is there some way I can indicate to data migrations that my database is up-to-date and doesn't need any migrations running on it? What should I do?

推荐答案

我找到了一种方法来表明我的数据库是最新的,并且(不足为奇)基于修改 __ MigrationHistory 表,代码优先迁移用于确定在运行 Update-Database时哪些迁移应用于数据库

I've found a way to indicate that my database is up-to-date, and it's (unsurprisingly) based on modifying the __MigrationHistory table, which code-first migrations uses to determine which migrations to apply to the DB when you run Update-Database.

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

By the way, whilst researching this answer I came across a very nice reference for code-first migrations commands, which can be found at: http://dotnet.dzone.com/articles/ef-migrations-command

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

When the database is created from scratch automatically by EF, it will always put a single entry into the __MigrationHistory table, and that entry will have the MigrationId (currentDateTime)_InitialCreate. This represents the initial creation of the database that EF has just carried out. However, your migration history is not going to begin with that MigrationId because you will have started with something else.

要愚弄代码优先的迁移,以为您认为关于最新的迁移,您需要从新的 __ MigrationHistory 表中删除该(currentDateTime)_InitialCreate 条目,创建数据库,然后插入如果您仍然有已对其应用迁移的旧数据库。

To "fool" code-first migrations into thinking that you're on the latest migration, you need to delete that (currentDateTime)_InitialCreate entry from the __MigrationHistory table of the newly-created DB, and insert what would have been there if you still had the old DB which had had the migrations applied to it.

因此,首先从新数据库中删除所有内容,生成数据库的 __ MigrationHistory 表。然后,进入程序包管理器控制台并运行:

So, first delete everything from the newly-generated DB's __MigrationHistory table. Then, go into package manager console and run:

PM> Update-Database -Script

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

From the resulting SQL script, pull out all the lines beginning with:

INSERT INTO [__MigrationHistory]...

然后,在新创建的数据库的上下文中运行那些 INSERT 语句。检查您的 __ MigrationHistory 表中现在是否存在这些行。下次运行时:

Then, run those INSERT statements within the context of the newly-created database. Check that each of those rows now exists in your __MigrationHistory table. When you next run:

PM> Update-Database

...,您应该会收到一条消息,提示没有基于代码的挂起迁移。祝贺您-您已经欺骗了代码优先迁移,以为您现在就在进行最新迁移,那么您可以继续从此处添加新迁移的地方继续。

... you should get a message saying "No pending code-based migrations." Congratulations - you've fooled code-first migrations into thinking you're now on the latest migration, and you can continue where you left off adding new migrations from here.

我确实认为应该以某种自动方式将其内置到EF代码中,但是...也许他们应该添加以下内容:

I do think there should be some automated way of doing this built into EF code-first, though... maybe they should add something like:

PM> Update-Database -MigrationsTableOnly

...这样,它将破坏迁移表中的现有条目,并且只需将新条目插入到项目中定义的每个迁移的迁移历史记录中,但实际上不尝试运行迁移。嗯。

... whereby it would clobber the existing entries in the migrations table, and just insert the new entries into migrations history for each migration defined in your project, but not actually try and run the migrations. Ah well.

更新

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

UPDATE
I've found a way to automate this nicely, using a custom initializer's Seed method. Basically the Seed method deletes the existing migration history data when the DB is created, and inserts your migrations history. In my database context constructor, I register the custom initializer like so:

public class MyDatabaseContext : DbContext {
    public MyDatabaseContext() : base() {
        Database.SetInitializer(new MyDatabaseContextMigrationHistoryInitializer());
    }

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

The custom initializer itself looks like this:

/// <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')");
    }
}

这篇关于如何使用新生成的数据库添加新的代码优先迁移?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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