Сценарий Invoke-SqlCmd для миграции завершается неудачно в столбцах, которые будут представлены - PullRequest
0 голосов
/ 09 января 2019

Я пытаюсь получить миграцию базы данных в своем определении конвейера выпуска, примерно следуя этому подходу - dotnet ef migrations script --idempotent как части конвейера сборки, а затем задаче Invoke-SqlCmd, указывающей на полученный скрипт как часть конвейера выпуска.

Однако я внес одно изменение в этот пост в блоге, что может иметь важное значение: во избежание поврежденных состояний, в которых развернута половина миграции, я обертываю весь сценарий в транзакцию, чтобы она была эффективной

SET XACT_ABORT ON

BEGIN TRANSACTION

-- output of dotnet ef migrations script --idempotent

COMMIT

Однако, когда я пытаюсь запустить сценарий как часть моего конвейера выпуска, в задаче базы данных SQL Azure, точно так же, как та, которую он использует в сообщении в блоге, он завершается ошибкой, например, в. ссылки на вещи, которые еще не существуют в схеме, но к тому моменту, когда сценарий достигнет той части, которая включает ссылку.

Например, с учетом следующего скрипта миграции:

SET XACT_ABORT ON

BEGIN TRANSACTION
-- in the actual script, each of these statements are, individually, wrapped in an IF that
-- checks whether the migration has been run before or not, similar to the first one in
-- this listing

IF NOT EXISTS (SELECT * FROM [__EFMigrationsHistory] WHERE MigrationId = 'AddColumnBar')
BEGIN
    ALTER TABLE Foo ADD Bar int NULL
END

GO

UPDATE Foo SET Bar = 3
GO

ALTER TABLE Foo ALTER COLUMN Bar int NOT NULL
GO

COMMIT

Выполнение этого сценария с Invoke-SqlCmd, как предлагается в сообщении в блоге, приводит к ошибке, указывающей, что столбец Foo не существует.

Как мне сказать Invoke-SqlCmd, что я знаю, что нет, но будет, когда это необходимо? Если это невозможно, как лучше всего исправить этот процесс развертывания для DevOps Azure?


Дополнительная информация:

Вот полный журнал из шага SQL в конвейере выпуска:

2019-01-09T14:57:52.7983184Z ##[section]Starting: Apply EF Migrations
2019-01-09T14:57:52.7989024Z ==============================================================================
2019-01-09T14:57:52.7989311Z Task         : Azure SQL Database Deployment
2019-01-09T14:57:52.7989427Z Description  : Deploy Azure SQL DB using DACPAC or run scripts using SQLCMD
2019-01-09T14:57:52.7989514Z Version      : 1.2.9
2019-01-09T14:57:52.7989608Z Author       : Microsoft Corporation
2019-01-09T14:57:52.7989703Z Help         : [More Information](https://aka.ms/sqlazuredeployreadme)
2019-01-09T14:57:52.7989823Z ==============================================================================
2019-01-09T14:57:58.8012013Z Sql file: D:\a\r1\a\_db-migrations\migrations-with-transaction.sql
2019-01-09T14:57:58.8189093Z Invoke-Sqlcmd -ServerInstance "***" -Database "***" -Username "***"  -Password ******  -Inputfile "D:\a\r1\a\db-migrations\migrations-with-transaction.sql"  -ConnectionTimeout 120
2019-01-09T14:58:04.3140758Z ##[error]Invalid column name 'Group_DocumentTagGroupId'.Check out how to troubleshoot failures at https://aka.ms/sqlazuredeployreadme#troubleshooting-
2019-01-09T14:58:04.3480044Z ##[section]Finishing: Apply EF Migrations

Вот все ссылки на Group_DocumentTagGroupId в сценарии:

-- starting around line 1740
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20181026122735_AddEntityForDocumentTagGroup')
BEGIN
    ALTER TABLE [DocumentTags] ADD [Group_DocumentTagGroupId] bigint NOT NULL DEFAULT 0;
END;

GO

-- about 20 lines with no mention of the column (but several GO statements)

IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20181026122735_AddEntityForDocumentTagGroup')
BEGIN
    EXEC('
                    UPDATE [dbo].[DocumentTags] SET [Group_DocumentTagGroupId] = (SELECT TOP 1 [DocumentTagGroupId] FROM [dbo].[DocumentTagGroups] g WHERE g.[Name] = [Type])')
END;

GO

IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20181026122735_AddEntityForDocumentTagGroup')
BEGIN
    CREATE INDEX [IX_DocumentTags_Group_DocumentTagGroupId] ON [DocumentTags] ([Group_DocumentTagGroupId]);
END;

GO

IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20181026122735_AddEntityForDocumentTagGroup')
BEGIN
    ALTER TABLE [DocumentTags] ADD CONSTRAINT [FK_DocumentTags_DocumentTagGroups_Group_DocumentTagGroupId] FOREIGN KEY ([Group_DocumentTagGroupId]) REFERENCES [DocumentTagGroups] ([DocumentTagGroupId]) ON DELETE CASCADE;
END;

GO

Файл SQL, отправляемый в Invoke-SqlCmd, создается с помощью следующего сценария PowerShell

$migrationsWithoutTransaction = "./Migrations/scripts/migrations-without-transaction.sql"
dotnet ef migrations script --configuration Release --idempotent --output $migrationsWithoutTransaction

$migrationsWithTransaction = "./Migrations/scripts/migrations-with-transaction.sql"
Get-Content "./Migrations/begin-transaction.sql" | Out-File -Encoding Utf8 $migrationsWithTransaction
Get-Content $migrationsWithoutTransaction | Out-File -Encoding Utf8 -Append $migrationsWithTransaction
Get-Content "./Migrations/commit-transaction.sql" | Out-File -Encoding Utf8 -Append  $migrationsWithTransaction

где это содержимое вспомогательных сценариев sql:

-- Migrations/begin-transaction.sql
SET XACT_ABORT ON

BEGIN TRANSACTION

-- Migrations/end-transaction.sql
COMMIT
...