From 1955a6a1377fb852e65023953ef2c7c198aaaa73 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 01:04:00 +0000 Subject: [PATCH 1/8] Initial plan From 5ce419b272bc98a0119c1ca866db9e4cdcf4bcf8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 01:26:13 +0000 Subject: [PATCH 2/8] Fix migration script to emit batch terminators between commands within transactions In GenerateSqlScript, always emit batch terminator (GO for SQL Server) after BEGIN TRANSACTION and between individual commands, even within a transaction. This ensures that SQL statements like CREATE VIEW, which must be the first statement in a batch, work correctly in generated migration scripts. Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Migrations/Internal/Migrator.cs | 12 +-- .../MigrationsInfrastructureSqlServerTest.cs | 75 +++++++++++++++++++ .../MigrationsInfrastructureSqliteTest.cs | 18 +++++ 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs index a767c77be06..de2457b7037 100644 --- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs +++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs @@ -645,7 +645,8 @@ private static void GenerateSqlScript( if (!transactionStarted && !command.TransactionSuppressed) { builder - .AppendLine(sqlGenerationHelper.StartTransactionStatement); + .AppendLine(sqlGenerationHelper.StartTransactionStatement) + .Append(sqlGenerationHelper.BatchTerminator); transactionStarted = true; } @@ -674,14 +675,7 @@ private static void GenerateSqlScript( builder.Append(command.CommandText); } - if (!transactionStarted) - { - builder.Append(sqlGenerationHelper.BatchTerminator); - } - else - { - builder.Append(Environment.NewLine); - } + builder.Append(sqlGenerationHelper.BatchTerminator); } if (transactionStarted) diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs index 2984e17b476..4fc4c20c4a7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs @@ -90,24 +90,32 @@ CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) GO BEGIN TRANSACTION; +GO + CREATE TABLE [Table1] ( [Id] int NOT NULL, [Foo] int NOT NULL, [Description] nvarchar(max) NOT NULL, CONSTRAINT [PK_Table1] PRIMARY KEY ([Id]) ); +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000001_Migration1', N'7.0.0-test'); +GO COMMIT; GO BEGIN TRANSACTION; +GO + EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); +GO COMMIT; GO @@ -155,29 +163,39 @@ INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) GO BEGIN TRANSACTION; +GO + INSERT INTO Table1 (Id, Bar, Description) VALUES (-1, 3, 'Value With Empty Lines') +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000005_Migration5', N'7.0.0-test'); +GO COMMIT; GO BEGIN TRANSACTION; +GO + INSERT INTO Table1 (Id, Bar, Description) VALUES (-2, 4, 'GO Value With Empty Lines') +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000006_Migration6', N'7.0.0-test'); +GO COMMIT; GO BEGIN TRANSACTION; +GO + INSERT INTO Table1 (Id, Bar, Description) VALUES (-3, 5, '--Start GO Value With @@ -187,62 +205,87 @@ Value With Empty Lines; GO ') +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000007_Migration7', N'7.0.0-test'); +GO COMMIT; GO BEGIN TRANSACTION; +GO + DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000007_Migration7'; +GO COMMIT; GO BEGIN TRANSACTION; +GO + DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000006_Migration6'; +GO COMMIT; GO BEGIN TRANSACTION; +GO + DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000005_Migration5'; +GO COMMIT; GO BEGIN TRANSACTION; +GO + DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000004_Migration4'; +GO COMMIT; GO BEGIN TRANSACTION; +GO + DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000003_Migration3'; +GO COMMIT; GO BEGIN TRANSACTION; +GO + EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; +GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; +GO COMMIT; GO BEGIN TRANSACTION; +GO + DROP TABLE [Table1]; +GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1'; +GO COMMIT; GO @@ -411,19 +454,27 @@ public override async Task Can_generate_one_up_and_down_script() Assert.Equal( """ BEGIN TRANSACTION; +GO + EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); +GO COMMIT; GO BEGIN TRANSACTION; +GO + EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; +GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; +GO COMMIT; GO @@ -441,19 +492,27 @@ public override async Task Can_generate_up_and_down_script_using_names() Assert.Equal( """ BEGIN TRANSACTION; +GO + EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); +GO COMMIT; GO BEGIN TRANSACTION; +GO + EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; +GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; +GO COMMIT; GO @@ -481,6 +540,8 @@ CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) GO BEGIN TRANSACTION; +GO + IF NOT EXISTS ( SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1' @@ -493,6 +554,7 @@ [Description] nvarchar(max) NOT NULL, CONSTRAINT [PK_Table1] PRIMARY KEY ([Id]) ); END; +GO IF NOT EXISTS ( SELECT * FROM [__EFMigrationsHistory] @@ -502,11 +564,14 @@ IF NOT EXISTS ( INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000001_Migration1', N'7.0.0-test'); END; +GO COMMIT; GO BEGIN TRANSACTION; +GO + IF NOT EXISTS ( SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2' @@ -514,6 +579,7 @@ IF NOT EXISTS ( BEGIN EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; END; +GO IF NOT EXISTS ( SELECT * FROM [__EFMigrationsHistory] @@ -523,11 +589,14 @@ IF NOT EXISTS ( INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); END; +GO COMMIT; GO BEGIN TRANSACTION; +GO + IF EXISTS ( SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2' @@ -535,6 +604,7 @@ IF EXISTS ( BEGIN EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; END; +GO IF EXISTS ( SELECT * FROM [__EFMigrationsHistory] @@ -544,11 +614,14 @@ IF EXISTS ( DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; END; +GO COMMIT; GO BEGIN TRANSACTION; +GO + IF EXISTS ( SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1' @@ -556,6 +629,7 @@ IF EXISTS ( BEGIN DROP TABLE [Table1]; END; +GO IF EXISTS ( SELECT * FROM [__EFMigrationsHistory] @@ -565,6 +639,7 @@ IF EXISTS ( DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1'; END; +GO COMMIT; GO diff --git a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs index c57a2a2f098..1bb2530dbba 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs @@ -59,6 +59,7 @@ public override async Task Can_generate_up_and_down_scripts() ); BEGIN TRANSACTION; + CREATE TABLE "Table1" ( "Id" INTEGER NOT NULL CONSTRAINT "PK_Table1" PRIMARY KEY, "Foo" INTEGER NOT NULL, @@ -71,6 +72,7 @@ public override async Task Can_generate_up_and_down_scripts() COMMIT; BEGIN TRANSACTION; + ALTER TABLE "Table1" RENAME COLUMN "Foo" TO "Bar"; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") @@ -79,66 +81,77 @@ public override async Task Can_generate_up_and_down_scripts() COMMIT; BEGIN TRANSACTION; + INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000003_Migration3', '7.0.0-test'); COMMIT; BEGIN TRANSACTION; + INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000004_Migration4', '7.0.0-test'); COMMIT; BEGIN TRANSACTION; + INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000005_Migration5', '7.0.0-test'); COMMIT; BEGIN TRANSACTION; + INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000006_Migration6', '7.0.0-test'); COMMIT; BEGIN TRANSACTION; + INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000007_Migration7', '7.0.0-test'); COMMIT; BEGIN TRANSACTION; + DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000007_Migration7'; COMMIT; BEGIN TRANSACTION; + DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000006_Migration6'; COMMIT; BEGIN TRANSACTION; + DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000005_Migration5'; COMMIT; BEGIN TRANSACTION; + DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000004_Migration4'; COMMIT; BEGIN TRANSACTION; + DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000003_Migration3'; COMMIT; BEGIN TRANSACTION; + ALTER TABLE "Table1" RENAME COLUMN "Bar" TO "Foo"; DELETE FROM "__EFMigrationsHistory" @@ -147,6 +160,7 @@ DELETE FROM "__EFMigrationsHistory" COMMIT; BEGIN TRANSACTION; + DROP TABLE "Table1"; DELETE FROM "__EFMigrationsHistory" @@ -238,6 +252,7 @@ public override async Task Can_generate_one_up_and_down_script() Assert.Equal( """ BEGIN TRANSACTION; + ALTER TABLE "Table1" RENAME COLUMN "Foo" TO "Bar"; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") @@ -246,6 +261,7 @@ public override async Task Can_generate_one_up_and_down_script() COMMIT; BEGIN TRANSACTION; + ALTER TABLE "Table1" RENAME COLUMN "Bar" TO "Foo"; DELETE FROM "__EFMigrationsHistory" @@ -266,6 +282,7 @@ public override async Task Can_generate_up_and_down_script_using_names() Assert.Equal( """ BEGIN TRANSACTION; + ALTER TABLE "Table1" RENAME COLUMN "Foo" TO "Bar"; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") @@ -274,6 +291,7 @@ public override async Task Can_generate_up_and_down_script_using_names() COMMIT; BEGIN TRANSACTION; + ALTER TABLE "Table1" RENAME COLUMN "Bar" TO "Foo"; DELETE FROM "__EFMigrationsHistory" From 5f294ad17004516a2d1171407b7e1c35fd4c6fc4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 01:57:56 +0000 Subject: [PATCH 3/8] Keep BEGIN TRANSACTION and COMMIT in the same batch as commands Address review feedback: instead of isolating BEGIN TRANSACTION and COMMIT in their own GO-terminated batches, keep them in the same batch as their adjacent commands. GO separators now only appear between individual commands within a transaction. Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Migrations/Internal/Migrator.cs | 17 +++- .../MigrationsInfrastructureSqlServerTest.cs | 80 ------------------- .../MigrationsInfrastructureSqliteTest.cs | 36 --------- 3 files changed, 14 insertions(+), 119 deletions(-) diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs index de2457b7037..67a395d9d6e 100644 --- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs +++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs @@ -638,6 +638,7 @@ private static void GenerateSqlScript( string? idempotencyEnd = null) { var transactionStarted = false; + var isFirstCommandInTransaction = false; foreach (var command in commands) { if (!noTransactions) @@ -645,9 +646,9 @@ private static void GenerateSqlScript( if (!transactionStarted && !command.TransactionSuppressed) { builder - .AppendLine(sqlGenerationHelper.StartTransactionStatement) - .Append(sqlGenerationHelper.BatchTerminator); + .AppendLine(sqlGenerationHelper.StartTransactionStatement); transactionStarted = true; + isFirstCommandInTransaction = true; } if (transactionStarted && command.TransactionSuppressed) @@ -659,6 +660,13 @@ private static void GenerateSqlScript( } } + if (transactionStarted && !isFirstCommandInTransaction) + { + builder.Append(sqlGenerationHelper.BatchTerminator); + } + + isFirstCommandInTransaction = false; + if (idempotencyCondition != null && idempotencyEnd != null) { @@ -675,7 +683,10 @@ private static void GenerateSqlScript( builder.Append(command.CommandText); } - builder.Append(sqlGenerationHelper.BatchTerminator); + if (!transactionStarted) + { + builder.Append(sqlGenerationHelper.BatchTerminator); + } } if (transactionStarted) diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs index 4fc4c20c4a7..57dae985530 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs @@ -90,8 +90,6 @@ CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) GO BEGIN TRANSACTION; -GO - CREATE TABLE [Table1] ( [Id] int NOT NULL, [Foo] int NOT NULL, @@ -102,21 +100,15 @@ CONSTRAINT [PK_Table1] PRIMARY KEY ([Id]) INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000001_Migration1', N'7.0.0-test'); -GO - COMMIT; GO BEGIN TRANSACTION; -GO - EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); -GO - COMMIT; GO @@ -163,8 +155,6 @@ INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) GO BEGIN TRANSACTION; -GO - INSERT INTO Table1 (Id, Bar, Description) VALUES (-1, 3, 'Value With Empty Lines') @@ -172,14 +162,10 @@ INSERT INTO Table1 (Id, Bar, Description) VALUES (-1, 3, 'Value With INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000005_Migration5', N'7.0.0-test'); -GO - COMMIT; GO BEGIN TRANSACTION; -GO - INSERT INTO Table1 (Id, Bar, Description) VALUES (-2, 4, 'GO Value With @@ -188,14 +174,10 @@ Value With INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000006_Migration6', N'7.0.0-test'); -GO - COMMIT; GO BEGIN TRANSACTION; -GO - INSERT INTO Table1 (Id, Bar, Description) VALUES (-3, 5, '--Start GO Value With @@ -209,84 +191,54 @@ Value With INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000007_Migration7', N'7.0.0-test'); -GO - COMMIT; GO BEGIN TRANSACTION; -GO - DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000007_Migration7'; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000006_Migration6'; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000005_Migration5'; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000004_Migration4'; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000003_Migration3'; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - DROP TABLE [Table1]; GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1'; -GO - COMMIT; GO @@ -454,28 +406,20 @@ public override async Task Can_generate_one_up_and_down_script() Assert.Equal( """ BEGIN TRANSACTION; -GO - EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); -GO - COMMIT; GO BEGIN TRANSACTION; -GO - EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; -GO - COMMIT; GO @@ -492,28 +436,20 @@ public override async Task Can_generate_up_and_down_script_using_names() Assert.Equal( """ BEGIN TRANSACTION; -GO - EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); -GO - COMMIT; GO BEGIN TRANSACTION; -GO - EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; -GO - COMMIT; GO @@ -540,8 +476,6 @@ CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) GO BEGIN TRANSACTION; -GO - IF NOT EXISTS ( SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1' @@ -564,14 +498,10 @@ IF NOT EXISTS ( INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000001_Migration1', N'7.0.0-test'); END; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - IF NOT EXISTS ( SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2' @@ -589,14 +519,10 @@ IF NOT EXISTS ( INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); END; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - IF EXISTS ( SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2' @@ -614,14 +540,10 @@ IF EXISTS ( DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; END; -GO - COMMIT; GO BEGIN TRANSACTION; -GO - IF EXISTS ( SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1' @@ -639,8 +561,6 @@ IF EXISTS ( DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1'; END; -GO - COMMIT; GO diff --git a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs index 1bb2530dbba..18d8f724d5d 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs @@ -59,7 +59,6 @@ public override async Task Can_generate_up_and_down_scripts() ); BEGIN TRANSACTION; - CREATE TABLE "Table1" ( "Id" INTEGER NOT NULL CONSTRAINT "PK_Table1" PRIMARY KEY, "Foo" INTEGER NOT NULL, @@ -68,104 +67,77 @@ public override async Task Can_generate_up_and_down_scripts() INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000001_Migration1', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - ALTER TABLE "Table1" RENAME COLUMN "Foo" TO "Bar"; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000002_Migration2', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000003_Migration3', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000004_Migration4', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000005_Migration5', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000006_Migration6', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000007_Migration7', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000007_Migration7'; - COMMIT; BEGIN TRANSACTION; - DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000006_Migration6'; - COMMIT; BEGIN TRANSACTION; - DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000005_Migration5'; - COMMIT; BEGIN TRANSACTION; - DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000004_Migration4'; - COMMIT; BEGIN TRANSACTION; - DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000003_Migration3'; - COMMIT; BEGIN TRANSACTION; - ALTER TABLE "Table1" RENAME COLUMN "Bar" TO "Foo"; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000002_Migration2'; - COMMIT; BEGIN TRANSACTION; - DROP TABLE "Table1"; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000001_Migration1'; - COMMIT; @@ -252,21 +224,17 @@ public override async Task Can_generate_one_up_and_down_script() Assert.Equal( """ BEGIN TRANSACTION; - ALTER TABLE "Table1" RENAME COLUMN "Foo" TO "Bar"; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000002_Migration2', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - ALTER TABLE "Table1" RENAME COLUMN "Bar" TO "Foo"; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000002_Migration2'; - COMMIT; @@ -282,21 +250,17 @@ public override async Task Can_generate_up_and_down_script_using_names() Assert.Equal( """ BEGIN TRANSACTION; - ALTER TABLE "Table1" RENAME COLUMN "Foo" TO "Bar"; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000002_Migration2', '7.0.0-test'); - COMMIT; BEGIN TRANSACTION; - ALTER TABLE "Table1" RENAME COLUMN "Bar" TO "Foo"; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000002_Migration2'; - COMMIT; From a5867c849b5dfeb41c6f5ea56d2db3536109646b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 02:15:20 +0000 Subject: [PATCH 4/8] Revert Migrator.cs change; fix GO handling in SqlServerMigrationsSqlGenerator for script mode Instead of changing Migrator.GenerateSqlScript, fix at the source: SqlServerMigrationsSqlGenerator.Generate(SqlOperation) now embeds batch terminators directly in the command text when generating for scripts (Options.HasFlag(Script)), producing a single MigrationCommand with GO separators preserved. For non-script execution, behavior is unchanged (separate MigrationCommands per batch). Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Migrations/Internal/Migrator.cs | 13 +++---- .../SqlServerMigrationsSqlGenerator.cs | 24 +++++++++++-- .../MigrationsInfrastructureSqlServerTest.cs | 35 +++++++++++-------- .../MigrationsInfrastructureSqliteTest.cs | 18 ++++++++++ 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/src/EFCore.Relational/Migrations/Internal/Migrator.cs b/src/EFCore.Relational/Migrations/Internal/Migrator.cs index 67a395d9d6e..a767c77be06 100644 --- a/src/EFCore.Relational/Migrations/Internal/Migrator.cs +++ b/src/EFCore.Relational/Migrations/Internal/Migrator.cs @@ -638,7 +638,6 @@ private static void GenerateSqlScript( string? idempotencyEnd = null) { var transactionStarted = false; - var isFirstCommandInTransaction = false; foreach (var command in commands) { if (!noTransactions) @@ -648,7 +647,6 @@ private static void GenerateSqlScript( builder .AppendLine(sqlGenerationHelper.StartTransactionStatement); transactionStarted = true; - isFirstCommandInTransaction = true; } if (transactionStarted && command.TransactionSuppressed) @@ -660,13 +658,6 @@ private static void GenerateSqlScript( } } - if (transactionStarted && !isFirstCommandInTransaction) - { - builder.Append(sqlGenerationHelper.BatchTerminator); - } - - isFirstCommandInTransaction = false; - if (idempotencyCondition != null && idempotencyEnd != null) { @@ -687,6 +678,10 @@ private static void GenerateSqlScript( { builder.Append(sqlGenerationHelper.BatchTerminator); } + else + { + builder.Append(Environment.NewLine); + } } if (transactionStarted) diff --git a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs index 5397181e7a8..31f050b0a17 100644 --- a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs +++ b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs @@ -1587,6 +1587,8 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio .Replace("\\\r\n", "") .Split(["\r\n", "\n"], StringSplitOptions.None); + var isScript = Options.HasFlag(MigrationsSqlGenerationOptions.Script); + var hasPendingBatch = false; var state = ParsingState.Normal; var batchBuilder = new StringBuilder(); foreach (var line in preBatched) @@ -1650,6 +1652,11 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio AppendBatch(batchBuilder.ToString()); + if (isScript && hasPendingBatch) + { + EndStatement(builder, operation.SuppressTransaction); + } + ParsingState ConsumeAndReturn(ref int index, ParsingState newState) { index++; @@ -1660,8 +1667,21 @@ void AppendBatch(string batch) { if (!string.IsNullOrWhiteSpace(batch)) { - builder.Append(batch); - EndStatement(builder, operation.SuppressTransaction); + if (isScript) + { + if (hasPendingBatch) + { + builder.Append(Dependencies.SqlGenerationHelper.BatchTerminator); + } + + builder.Append(batch); + hasPendingBatch = true; + } + else + { + builder.Append(batch); + EndStatement(builder, operation.SuppressTransaction); + } } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs index 57dae985530..2984e17b476 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs @@ -96,19 +96,19 @@ CREATE TABLE [Table1] ( [Description] nvarchar(max) NOT NULL, CONSTRAINT [PK_Table1] PRIMARY KEY ([Id]) ); -GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000001_Migration1', N'7.0.0-test'); + COMMIT; GO BEGIN TRANSACTION; EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; -GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); + COMMIT; GO @@ -158,10 +158,10 @@ INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) INSERT INTO Table1 (Id, Bar, Description) VALUES (-1, 3, 'Value With Empty Lines') -GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000005_Migration5', N'7.0.0-test'); + COMMIT; GO @@ -170,10 +170,10 @@ INSERT INTO Table1 (Id, Bar, Description) VALUES (-2, 4, 'GO Value With Empty Lines') -GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000006_Migration6', N'7.0.0-test'); + COMMIT; GO @@ -187,58 +187,63 @@ Value With Empty Lines; GO ') -GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000007_Migration7', N'7.0.0-test'); + COMMIT; GO BEGIN TRANSACTION; DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000007_Migration7'; + COMMIT; GO BEGIN TRANSACTION; DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000006_Migration6'; + COMMIT; GO BEGIN TRANSACTION; DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000005_Migration5'; + COMMIT; GO BEGIN TRANSACTION; DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000004_Migration4'; + COMMIT; GO BEGIN TRANSACTION; DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000003_Migration3'; + COMMIT; GO BEGIN TRANSACTION; EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; -GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; + COMMIT; GO BEGIN TRANSACTION; DROP TABLE [Table1]; -GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1'; + COMMIT; GO @@ -407,19 +412,19 @@ public override async Task Can_generate_one_up_and_down_script() """ BEGIN TRANSACTION; EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; -GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); + COMMIT; GO BEGIN TRANSACTION; EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; -GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; + COMMIT; GO @@ -437,19 +442,19 @@ public override async Task Can_generate_up_and_down_script_using_names() """ BEGIN TRANSACTION; EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; -GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); + COMMIT; GO BEGIN TRANSACTION; EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; -GO DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; + COMMIT; GO @@ -488,7 +493,6 @@ [Description] nvarchar(max) NOT NULL, CONSTRAINT [PK_Table1] PRIMARY KEY ([Id]) ); END; -GO IF NOT EXISTS ( SELECT * FROM [__EFMigrationsHistory] @@ -498,6 +502,7 @@ IF NOT EXISTS ( INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000001_Migration1', N'7.0.0-test'); END; + COMMIT; GO @@ -509,7 +514,6 @@ IF NOT EXISTS ( BEGIN EXEC sp_rename N'[Table1].[Foo]', N'Bar', 'COLUMN'; END; -GO IF NOT EXISTS ( SELECT * FROM [__EFMigrationsHistory] @@ -519,6 +523,7 @@ IF NOT EXISTS ( INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000002_Migration2', N'7.0.0-test'); END; + COMMIT; GO @@ -530,7 +535,6 @@ IF EXISTS ( BEGIN EXEC sp_rename N'[Table1].[Bar]', N'Foo', 'COLUMN'; END; -GO IF EXISTS ( SELECT * FROM [__EFMigrationsHistory] @@ -540,6 +544,7 @@ IF EXISTS ( DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000002_Migration2'; END; + COMMIT; GO @@ -551,7 +556,6 @@ IF EXISTS ( BEGIN DROP TABLE [Table1]; END; -GO IF EXISTS ( SELECT * FROM [__EFMigrationsHistory] @@ -561,6 +565,7 @@ IF EXISTS ( DELETE FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'00000000000001_Migration1'; END; + COMMIT; GO diff --git a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs index 18d8f724d5d..c57a2a2f098 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsInfrastructureSqliteTest.cs @@ -67,6 +67,7 @@ public override async Task Can_generate_up_and_down_scripts() INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000001_Migration1', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; @@ -74,56 +75,67 @@ public override async Task Can_generate_up_and_down_scripts() INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000002_Migration2', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000003_Migration3', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000004_Migration4', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000005_Migration5', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000006_Migration6', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000007_Migration7', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000007_Migration7'; + COMMIT; BEGIN TRANSACTION; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000006_Migration6'; + COMMIT; BEGIN TRANSACTION; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000005_Migration5'; + COMMIT; BEGIN TRANSACTION; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000004_Migration4'; + COMMIT; BEGIN TRANSACTION; DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000003_Migration3'; + COMMIT; BEGIN TRANSACTION; @@ -131,6 +143,7 @@ DELETE FROM "__EFMigrationsHistory" DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000002_Migration2'; + COMMIT; BEGIN TRANSACTION; @@ -138,6 +151,7 @@ DELETE FROM "__EFMigrationsHistory" DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000001_Migration1'; + COMMIT; @@ -228,6 +242,7 @@ public override async Task Can_generate_one_up_and_down_script() INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000002_Migration2', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; @@ -235,6 +250,7 @@ public override async Task Can_generate_one_up_and_down_script() DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000002_Migration2'; + COMMIT; @@ -254,6 +270,7 @@ public override async Task Can_generate_up_and_down_script_using_names() INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('00000000000002_Migration2', '7.0.0-test'); + COMMIT; BEGIN TRANSACTION; @@ -261,6 +278,7 @@ public override async Task Can_generate_up_and_down_script_using_names() DELETE FROM "__EFMigrationsHistory" WHERE "MigrationId" = '00000000000002_Migration2'; + COMMIT; From 687aae20cfaa524c55eeaaebc1431477ddcf26ae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 02:36:28 +0000 Subject: [PATCH 5/8] Add test for SqlOperation with suppressTransaction and multiple GO separators in script mode Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../SqlServerMigrationsSqlGeneratorTest.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs index effa2a16655..28e80de8a31 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs @@ -1311,6 +1311,30 @@ public virtual void SqlOperation_handles_multiple_delimiters_in_string() """); } + [ConditionalFact] + public virtual void SqlOperation_handles_go_in_script_with_suppress_transaction() + { + Generate( + new SqlOperation + { + Sql = "CREATE PROCEDURE dbo.Proc1 AS SELECT 1;" + EOL + "GO" + EOL + + "CREATE VIEW view1 AS SELECT 1 AS Id;" + EOL + "GO" + EOL + "SELECT 1;", + SuppressTransaction = true + }, + MigrationsSqlGenerationOptions.Script); + + AssertSql( + """ +CREATE PROCEDURE dbo.Proc1 AS SELECT 1; +GO + +CREATE VIEW view1 AS SELECT 1 AS Id; +GO + +SELECT 1; +"""); + } + public override void InsertDataOperation_all_args_spatial() { base.InsertDataOperation_all_args_spatial(); From e314e9b74cedc71ff55dac0de514aaabcf86da61 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 04:46:22 +0000 Subject: [PATCH 6/8] Preserve GO N count in script mode; update test to use GO 2 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../SqlServerMigrationsSqlGenerator.cs | 32 +++++++++++++++---- .../SqlServerMigrationsSqlGeneratorTest.cs | 4 +-- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs index 31f050b0a17..ab4f396a9e8 100644 --- a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs +++ b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs @@ -1591,6 +1591,7 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio var hasPendingBatch = false; var state = ParsingState.Normal; var batchBuilder = new StringBuilder(); + string? pendingTerminator = null; foreach (var line in preBatched) { var trimmed = line.TrimStart(); @@ -1603,14 +1604,25 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio var batch = batchBuilder.ToString(); batchBuilder.Clear(); - var count = trimmed.Length >= 4 - && int.TryParse(trimmed.AsSpan(3), out var specifiedCount) - ? specifiedCount - : 1; - - for (var j = 0; j < count; j++) + if (isScript) { AppendBatch(batch); + if (hasPendingBatch) + { + pendingTerminator = trimmed + Environment.NewLine + Environment.NewLine; + } + } + else + { + var count = trimmed.Length >= 4 + && int.TryParse(trimmed.AsSpan(3), out var specifiedCount) + ? specifiedCount + : 1; + + for (var j = 0; j < count; j++) + { + AppendBatch(batch); + } } } else @@ -1654,6 +1666,11 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio if (isScript && hasPendingBatch) { + if (pendingTerminator != null) + { + builder.Append(pendingTerminator); + } + EndStatement(builder, operation.SuppressTransaction); } @@ -1671,7 +1688,8 @@ void AppendBatch(string batch) { if (hasPendingBatch) { - builder.Append(Dependencies.SqlGenerationHelper.BatchTerminator); + builder.Append(pendingTerminator ?? Dependencies.SqlGenerationHelper.BatchTerminator); + pendingTerminator = null; } builder.Append(batch); diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs index 28e80de8a31..e6f75761879 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs @@ -1318,7 +1318,7 @@ public virtual void SqlOperation_handles_go_in_script_with_suppress_transaction( new SqlOperation { Sql = "CREATE PROCEDURE dbo.Proc1 AS SELECT 1;" + EOL + "GO" + EOL - + "CREATE VIEW view1 AS SELECT 1 AS Id;" + EOL + "GO" + EOL + "SELECT 1;", + + "CREATE VIEW view1 AS SELECT 1 AS Id;" + EOL + "GO 2" + EOL + "SELECT 1;", SuppressTransaction = true }, MigrationsSqlGenerationOptions.Script); @@ -1329,7 +1329,7 @@ public virtual void SqlOperation_handles_go_in_script_with_suppress_transaction( GO CREATE VIEW view1 AS SELECT 1 AS Id; -GO +GO 2 SELECT 1; """); From 64102e868cf72a3cfb3d0c9f03b698a310987bcc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 05:35:16 +0000 Subject: [PATCH 7/8] Simplify: skip GO parsing in script mode, pass SQL through as-is via base class Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../SqlServerMigrationsSqlGenerator.cs | 60 +++++-------------- .../SqlServerMigrationsSqlGeneratorTest.cs | 2 - 2 files changed, 14 insertions(+), 48 deletions(-) diff --git a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs index ab4f396a9e8..88b1bbcd4ac 100644 --- a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs +++ b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs @@ -1582,16 +1582,19 @@ private enum ParsingState /// The command builder to use to build the commands. protected override void Generate(SqlOperation operation, IModel? model, MigrationCommandListBuilder builder) { + if (Options.HasFlag(MigrationsSqlGenerationOptions.Script)) + { + base.Generate(operation, model, builder); + return; + } + var preBatched = operation.Sql .Replace("\\\n", "") .Replace("\\\r\n", "") .Split(["\r\n", "\n"], StringSplitOptions.None); - var isScript = Options.HasFlag(MigrationsSqlGenerationOptions.Script); - var hasPendingBatch = false; var state = ParsingState.Normal; var batchBuilder = new StringBuilder(); - string? pendingTerminator = null; foreach (var line in preBatched) { var trimmed = line.TrimStart(); @@ -1604,25 +1607,14 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio var batch = batchBuilder.ToString(); batchBuilder.Clear(); - if (isScript) + var count = trimmed.Length >= 4 + && int.TryParse(trimmed.AsSpan(3), out var specifiedCount) + ? specifiedCount + : 1; + + for (var j = 0; j < count; j++) { AppendBatch(batch); - if (hasPendingBatch) - { - pendingTerminator = trimmed + Environment.NewLine + Environment.NewLine; - } - } - else - { - var count = trimmed.Length >= 4 - && int.TryParse(trimmed.AsSpan(3), out var specifiedCount) - ? specifiedCount - : 1; - - for (var j = 0; j < count; j++) - { - AppendBatch(batch); - } } } else @@ -1664,16 +1656,6 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio AppendBatch(batchBuilder.ToString()); - if (isScript && hasPendingBatch) - { - if (pendingTerminator != null) - { - builder.Append(pendingTerminator); - } - - EndStatement(builder, operation.SuppressTransaction); - } - ParsingState ConsumeAndReturn(ref int index, ParsingState newState) { index++; @@ -1684,22 +1666,8 @@ void AppendBatch(string batch) { if (!string.IsNullOrWhiteSpace(batch)) { - if (isScript) - { - if (hasPendingBatch) - { - builder.Append(pendingTerminator ?? Dependencies.SqlGenerationHelper.BatchTerminator); - pendingTerminator = null; - } - - builder.Append(batch); - hasPendingBatch = true; - } - else - { - builder.Append(batch); - EndStatement(builder, operation.SuppressTransaction); - } + builder.Append(batch); + EndStatement(builder, operation.SuppressTransaction); } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs index e6f75761879..739869558b9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs @@ -1327,10 +1327,8 @@ public virtual void SqlOperation_handles_go_in_script_with_suppress_transaction( """ CREATE PROCEDURE dbo.Proc1 AS SELECT 1; GO - CREATE VIEW view1 AS SELECT 1 AS Id; GO 2 - SELECT 1; """); } From f17adbd8d53a068dc96465ef19b6a5b093240764 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 06:01:40 +0000 Subject: [PATCH 8/8] Append line end only if SQL doesn't end with one; update baselines for Can_generate_up_and_down_scripts Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Migrations/SqlServerMigrationsSqlGenerator.cs | 8 +++++++- .../Migrations/MigrationsInfrastructureSqlServerTest.cs | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs index 88b1bbcd4ac..2caaa043496 100644 --- a/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs +++ b/src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs @@ -1584,7 +1584,13 @@ protected override void Generate(SqlOperation operation, IModel? model, Migratio { if (Options.HasFlag(MigrationsSqlGenerationOptions.Script)) { - base.Generate(operation, model, builder); + builder.Append(operation.Sql); + if (!operation.Sql.EndsWith('\n')) + { + builder.AppendLine(); + } + + EndStatement(builder, operation.SuppressTransaction); return; } diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs index 2984e17b476..d0f28e435dd 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs @@ -144,11 +144,11 @@ SELECT @Counter END; GO - SELECT GetDate(); --GO SELECT GetDate() GO +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000004_Migration4', N'7.0.0-test'); @@ -320,11 +320,11 @@ SELECT @Counter END; GO - SELECT GetDate(); --GO SELECT GetDate() GO +GO INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) VALUES (N'00000000000004_Migration4', N'7.0.0-test');