2012-10-16 27 views
4

我想部署一個使用EF5 codefist和遷移構建的MVC4應用程序。MigrateDatabaseToLatestVersion和dbo .__ MigrationHistory

我希望應用程序來更新數據庫,當我在將來部署新的遷移應用程序的新版本,所以在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)這是建立一個應用程序的推薦方式,該應用程序會自動應用在新版本上重新啓動的新遷移。

回答

8

對於任何尋找答案的人來說,這裏還有另一個NASTY陷阱。檢查內容

[dbo].[__MigrationHistory] table column ContextKey 

該表格告訴我們如何創建數據庫(遷移模式,創建模式等)。以及遷移配置程序。我受到MigrationsConfiguration類名稱更改的傷害。

更改表中的條目工作:-)或重新命名您的代碼。

+1

踩在相同的耙子。如果要使用現有數據庫,則不應更改配置的名稱空間和類名稱。 –

1

1) 由於您的遷移被稱爲「初始」而不是「InitialCreate」,這意味着您手動創建了此項,並且當您啓用代碼第一次遷移時,數據庫已不存在。或者至少上下文並沒有指向它。 http://msdn.microsoft.com/en-us/data/jj591621.aspx

我相信MigrateDatabaseToLatestVersion將首先嚐試爲啓用遷移之前存在的實體創建實體表。由於InitialCreate遷移不存在於您的數據庫中,因此第一步將與已存在的表衝突。對不起,這有點含糊,但我不完全理解它。要解決這個問題,我會通過刪除它們(首先保存任何自定義更改)來刪除遷移,然後使用指向現有數據庫的上下文重新啓用它們。您現在應該有一個「InitialCreate」遷移。您現在應該能夠複製數據庫並在生產環境中使用MigrateDatabaseToLatestVersion。

2) 個人讓代碼第一次更新生產數據庫讓我很擔心。我一直在使用update-database -script -sourcemigration xx來生成遷移數據庫的腳本。這樣,你可以看到在破壞任何事情之前會發生什麼。它還允許您在事務中運行並在發生故障後回滾。

0

在我的情況下,這個問題是由於缺少遷移引起的。我對模型做了一些修改,但我忘了創建新的遷移文件。

我的解決辦法是在包管理器控制檯運行:添加遷移MyMigrationName

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) 
    { 
    } 
} 

添加行以上配置的構造之後,遷移運行,沒有任何問題。您可以檢查__MigrationHistory數據庫中哪些ContextKey值已被使用。