4

我正在尝试部署使用 EF5 codefist 和迁移构建的 MVC4 应用程序。

我希望应用程序在将来部署具有新迁移的新版本应用程序时更新数据库,因此在 Global.asax 中我这样做:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<GoDealMvc4Context, Configuration>());
using (var ctx = new GoDealMvc4Context()) {
    ctx.Database.Initialize(false);
}

服务器上的初始数据库是通过附加从我的开发机器复制的 MDF 文件来部署的。此数据库包含 __MigrationsHistory 系统表。所以这个数据库应该不需要执行任何迁移,因为它是最新的最新迁移。

当我尝试在服务器上启动应用程序时,我收到此错误:

There is already an object named 'UserProfile' in the database.

[SqlException (0x80131904): There is already an object named 'UserProfile' in the database.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +388
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +688
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +4403
System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout) +2755286
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) +527
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() +290
System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement) +247
System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements) +202
System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration) +472
System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId) +175
System.Data.Entity.MigrateDatabaseToLatestVersion`2.InitializeDatabase(TContext context) +150
System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action) +66
System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization() +225
System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input) +208
System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action) +235
GoDeal.Mvc4.MvcApplication.Application_Start() +342

因此,即使数据库中存在具有以下内容的 __MigrationHistory 表,应用程序显然认为它需要应用迁移:

MigrationId                 Model         ProductVersion
201210161046508_initial     0x1F8...      5.0.0.net45

该应用程序包含一个迁移类:

201210161046508_initial.cs:

public partial class initial : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.UserProfile",
            ....

所以我的问题是:1)当 __MigrationsHistory 表的内容如所述时,为什么我的应用程序认为需要应用此迁移。

2)这是推荐的制作应用程序的方法,该应用程序在新版本上重新启动时自动应用新迁移。

4

4 回答 4

8

对于任何寻找答案的人来说,这里还有另一个 NASTY gotcha。检查内容

[dbo].[__MigrationHistory]   table    column ContextKey

此表讲述了 DB 是如何创建的(迁移模式、创建模式等)。以及使用什么迁移配置程序。我因更改 MigrationsConfiguration 类名称而受到伤害。

更改表中的条目有效:-) 或重命名您的代码。

于 2013-04-22T14:13:47.007 回答
1

1) 由于您的迁移被称为“initial”而不是“InitialCreate”,这意味着您手动创建了它,并且当您启用代码首次迁移时,数据库还不存在。或者至少上下文没有指向它。http://msdn.microsoft.com/en-us/data/jj591621.aspx

我相信 MigrateDatabaseToLatestVersion 将首先尝试为启用迁移之前存在的实体创建实体表。由于您的数据库中不存在 InitialCreate 迁移,因此第一步将与已经存在的表发生冲突。对不起,这有点含糊,但我不完全理解。为了解决这个问题,我将通过删除它们(首先保存任何自定义更改)来删除迁移,然后使用指向现有数据库的上下文再次启用它们。您现在应该有一个“InitialCreate”迁移。您现在应该能够复制数据库并在生产环境中使用 MigrateDatabaseToLatestVersion。

2)我个人让代码首先更新生产数据库让我很担心。我一直在使用 update-database -script -sourcemigration xx 来生成脚本来迁移数据库。这样你就可以在破坏任何东西之前看到会发生什么。它还允许您在事务中运行并在失败后回滚。

于 2013-02-20T11:55:19.430 回答
0

就我而言,此问题是由于缺少迁移引起的。我对模型进行了一些更改,但我忘了创建新的迁移文件。

我的解决方案是在包管理器控制台中运行:Add-Migration MyMigrationName

于 2015-08-04T06:47:33.357 回答
0

以防其他人在使用自动迁移时更改模型后遇到SqlException该消息。There is already an object named '<TABLE_NAME>' in the database.在某些情况下,迁移的配置似乎需要明确命名上下文键:

internal sealed class Configuration : DbMigrationsConfiguration<MyDatabaseContext>
{
    public Configuration ()
    {
        AutomaticMigrationsEnabled = true;
        ContextKey = "MyNamespace.MyDatabaseContext"; // this line was missed
    }

    protected override void Seed(MyDatabaseContext context)
    {
    }
}

将上面的行添加到 Configuration 的构造函数后,迁移运行没有任何问题。您可以检查数据库ContextKey中已使用的值__MigrationHistory

于 2015-09-19T16:25:41.680 回答