Мы используем First Entity Framework 5.0 и автоматическую миграцию.
У меня был класс вроде:
public class TraversalZones
{
public int Low { get; set; }
public int High { get; set; }
}
Тогда мы поняли, что эти свойства на самом деле не являются правильными именами, поэтому мы изменили их:
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");
}
Затем я обновил db:
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')
Это кажется ошибкой в Migrations.