Первая миграция кода EF5: ошибка «Имена столбцов в каждой таблице должны быть уникальными» после использования RenameColumn
Мы'использовать Entity Framework 5.0 Code First и автоматические миграции.
У меня был такой класс:
public class TraversalZones
{
public int Low { get; set; }
public int High { get; set; }
}
Тогда мы поняли, что эти свойства не былиt действительно правильные имена, поэтому мы изменили их:
public class TraversalZones
{
public int Left { get; set; }
public int Top { get; set; }
}
Переименование реорганизовано должным образом на протяжении всего проекта, но я знаю, что автоматические миграции неЯ достаточно умен, чтобы подобрать эти явные переименования в IDE, поэтому сначала я проверил, что единственной ожидающей миграцией было переименование столбца:
update-database -f -script
Конечно же, он показал, что SQL отбрасывает Low и High и добавляет Left и Top. Затем я добавил ручную миграцию:
add-migration RenameColumns_TraversalZones_LowHigh_LeftTop
И исправил сгенерированный код так:
public override void Up()
{
RenameColumn("TraversalZones", "Low", "Left");
RenameColumn("TraversalZones", "High", "Top");
}
public override void Down()
{
RenameColumn("TraversalZones", "Left", "Low");
RenameColumn("TraversalZones", "Top", "High");
}
Затем я обновил БД:
update-database -verbose
И получил 2 переименования столбцов, как я и ожидал.
Спустя несколько миграций я создал резервную копию Production и восстановил ее в локальной БД для проверки кода на этой БД. В этой БД уже была создана таблица TraversalZones со старыми именами столбцов (Low и High), которые я, конечно, начал с ее обновления:
update-database -f -verbose
И команды переименования появились в выводе - все оказалось хорошо:
EXECUTE sp_rename @objname = N'TraversalZones.Low', @newname = N'Left', @objtype = N'COLUMN'
EXECUTE sp_rename @objname = N'TraversalZones.High', @newname = N'Top', @objtype = N'COLUMN'
[Inserting migration history record]
Затем я запустил свой код, и он допустил ошибку, сообщая, что база данных изменилась с момента последнего запуска, и что я должен запуститьupdate-database
...
Итак, я запустил его снова:
update-database -f -verbose
И теперь я застрял на этой ошибке:
No pending code-based migrations. Applying automatic migration:
201212191601545_AutomaticMigration.
ALTER TABLE [dbo].[TraversalZones] ADD [Left] [int] NOT NULL DEFAULT 0
System.Data.SqlClient.SqlException (0x80131904): Column names in each table must be unique. Column name 'Left' in table 'dbo.TraversalZones' is specified more than once.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable`1 operations, Boolean downgrading, Boolean auto)
at System.Data.Entity.Migrations.DbMigrator.AutoMigrate(String migrationId, XDocument sourceModel, XDocument targetModel, Boolean downgrading)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.AutoMigrate(String migrationId, XDocument sourceModel, XDocument targetModel, Boolean downgrading)
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
ClientConnectionId:c40408ee-def3-4553-a9fb-195366a05fff
Column names in each table must be unique. Column name 'Left' in table 'dbo.TraversalZones' is specified more than once.
Таким образом, ясно, что Миграции путают, является ли колонкаОставил" все еще нужно сделать это в эту таблицу; Я бы предположил, что RenameColumn оставит вещи в надлежащем состоянии, но, похоже, это не так.
Когда я бросаю то, что этопытается сделать сupdate-database -f -script
Я пытаюсь сделать именно то, что сделал бы, если бы не было ручной миграции:
ALTER TABLE [dbo].[TraversalZones] ADD [Left] [int] NOT NULL DEFAULT 0
ALTER TABLE [dbo].[TraversalZones] ADD [Top] [int] NOT NULL DEFAULT 0
DECLARE @var0 nvarchar(128)
SELECT @var0 = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'dbo.TraversalZones')
AND col_name(parent_object_id, parent_column_id) = 'Low';
IF @var0 IS NOT NULL
EXECUTE('ALTER TABLE [dbo].[TraversalZones] DROP CONSTRAINT ' + @var0)
ALTER TABLE [dbo].[TraversalZones] DROP COLUMN [Low]
DECLARE @var1 nvarchar(128)
SELECT @var1 = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'dbo.TraversalZones')
AND col_name(parent_object_id, parent_column_id) = 'High';
IF @var1 IS NOT NULL
EXECUTE('ALTER TABLE [dbo].[TraversalZones] DROP CONSTRAINT ' + @var1)
ALTER TABLE [dbo].[TraversalZones] DROP COLUMN [High]
INSERT INTO [__MigrationHistory] ([MigrationId], [Model], [ProductVersion]) VALUES ('201212191639471_AutomaticMigration', 0x1F8B08000...000, '5.0.0.net40')
Похоже, это ошибка в миграции.