我正在尝试部署使用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)这是制作应用程序的推荐方法,该应用程序会自动应用新版本重新启动的新版本。
答案 0 :(得分: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来生成迁移数据库的脚本。通过这种方式,您可以看到在破坏任何东西之前会发生什么。它还允许您在事务中运行并在发生故障后回滚。
答案 2 :(得分:0)
在我的情况下,此问题是由于缺少迁移造成的。我对模型进行了一些更改,但是我忘了创建新的迁移文件。
我的解决方案是在Package Manager控制台中运行:Add-Migration MyMigrationName
答案 3 :(得分:0)
以防其他人在使用自动迁移时更改模型后遇到SqlException
消息There is already an object named '<TABLE_NAME>' in the database.
。似乎是移民&#39;在某些情况下,配置需要显式命名上下文密钥:
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
值。