Skip to content

Preserve batch terminators in migration scripts for SQL operations with GO separators#37810

Merged
AndriySvyryd merged 8 commits intomainfrom
copilot/fix-migration-sql-script-output
Feb 27, 2026
Merged

Preserve batch terminators in migration scripts for SQL operations with GO separators#37810
AndriySvyryd merged 8 commits intomainfrom
copilot/fix-migration-sql-script-output

Conversation

Copy link
Contributor

Copilot AI commented Feb 27, 2026

Script-Migration strips GO batch separators from custom SQL within transactions, breaking statements like CREATE VIEW that must be the first statement in a batch.

// GO separators are parsed into separate MigrationCommands by SqlServerMigrationsSqlGenerator,
// but GenerateSqlScript only emitted newlines (not GO) between commands inside a transaction.
migrationBuilder.Sql("GO\r\nCREATE VIEW view1 AS SELECT 1 AS Id;\r\nGO");

Before: GO-separated batches within a single SqlOperation are split into separate MigrationCommands, which GenerateSqlScript then joins with newlines (not GO) inside transactions
After: In script generation mode, the GO parsing is skipped entirely and the raw SQL is passed through as-is, preserving all GO separators (including GO N count syntax) in the final script output. A line ending is appended only if the SQL doesn't already end with one, avoiding double newlines.

Changes

  • SqlServerMigrationsSqlGenerator.Generate(SqlOperation): When generating for a script (Options.HasFlag(MigrationsSqlGenerationOptions.Script)), skip GO parsing entirely and pass the raw SQL through as a single MigrationCommand via builder.Append. A trailing line ending is conditionally appended only if the SQL doesn't already end with \n. This preserves GO separators as-is in the generated script. For non-script execution, behavior is unchanged — GO separators still split into separate commands with count expansion as before.
  • Updated baselines: Updated expected output in Can_generate_up_and_down_scripts and Can_generate_up_and_down_scripts_noTransactions to reflect the raw SQL pass-through for Migration4 (which contains embedded GO separators with suppressTransaction: true).
  • New test: Added SqlOperation_handles_go_in_script_with_suppress_transaction test that verifies migrationBuilder.Sql with suppressTransaction: true and SQL containing multiple GO separators (including GO 2 with count) correctly preserves batch terminators in script generation mode.

This approach fixes the problem at the SQL generator level with minimal complexity — since script mode was parsing GO separators out just to reconstruct them, we avoid the parsing altogether and let the raw SQL flow through directly.

Original prompt

This section details on the original issue you should resolve

<issue_title>Migration sql script will output incorrect content when include create view command.</issue_title>
<issue_description>### Bug description

Create view command must be unique command in a batch, but script-migration command will remove ‘GO’ from custom sql. I need to re edit the output script text to fix the errors.

Your code

var sql = "GO\r\nCREATE VIEW view1 AS xxx;\r\nGO";
migrationBuilder.Sql(sql);

Script-Migration 0

Stack traces


Verbose output


EF Core version

10.0.0

Database provider

Microsoft.EntityFrameworkCore.SqlServer

Target framework

.Net 10.0

Operating system

No response

IDE

No response</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…n 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>
Copilot AI changed the title [WIP] Fix migration sql script output for create view command Emit batch terminators between commands within transactions in migration scripts Feb 27, 2026
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>
…enerator 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>
Copilot AI changed the title Emit batch terminators between commands within transactions in migration scripts Preserve batch terminators in migration scripts for SQL operations with GO separators Feb 27, 2026
…parators in script mode

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
…base class

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
…r Can_generate_up_and_down_scripts

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
@AndriySvyryd AndriySvyryd marked this pull request as ready for review February 27, 2026 08:09
@AndriySvyryd AndriySvyryd requested a review from a team as a code owner February 27, 2026 08:09
Copilot AI review requested due to automatic review settings February 27, 2026 08:09
@AndriySvyryd AndriySvyryd assigned roji and unassigned AndriySvyryd and Copilot Feb 27, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes an issue where Script-Migration strips GO batch separators from custom SQL within transactions, breaking statements like CREATE VIEW that must be the first statement in a batch.

Changes:

  • Modified SqlServerMigrationsSqlGenerator.Generate(SqlOperation) to skip GO parsing in script mode and pass raw SQL through as-is, preserving batch terminators literally
  • Added test case SqlOperation_handles_go_in_script_with_suppress_transaction to verify GO separators (including GO N count syntax) are preserved in script generation mode
  • Updated baselines to reflect the new behavior where embedded GO separators are preserved

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs Added early return in Script mode to pass raw SQL through without GO parsing, preserving batch terminators
test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs Added test verifying GO separators are preserved in script mode with suppressTransaction
test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsInfrastructureSqlServerTest.cs Updated baselines for two tests to reflect preserved GO separators in Migration4

@AndriySvyryd AndriySvyryd merged commit f254706 into main Feb 27, 2026
17 checks passed
@AndriySvyryd AndriySvyryd deleted the copilot/fix-migration-sql-script-output branch February 27, 2026 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migration sql script will output incorrect content when include create view command.

4 participants