Skip to content

SqlServer: preserve GO statements in scripted migrations#37632

Open
BurakBebek1 wants to merge 1 commit intodotnet:mainfrom
BurakBebek1:fix-script-go-handling-clean
Open

SqlServer: preserve GO statements in scripted migrations#37632
BurakBebek1 wants to merge 1 commit intodotnet:mainfrom
BurakBebek1:fix-script-go-handling-clean

Conversation

@BurakBebek1
Copy link

  • I've read the guidelines for contributing and seen the walkthrough
  • I've posted a comment on an issue with a detailed description of how I am planning to contribute and got approval from a member of the team
  • The code builds and tests pass locally (also verified by our automated build checks)
  • Commit messages follow this format:
        Summary of the changes
        - Detail 1
        - Detail 2

        Fixes #bugnumber
  • Tests for the changes have been added (for bug fixes / features)
  • Code follows the same patterns and style as existing code in this repo

Summary

When generating script migrations on SQL Server, GO statements should be treated as plain SQL text rather than batch delimiters. Currently, GO and GO <count> are incorrectly split even in script mode.

This PR ensures that GO is not interpreted as a batch separator when isScript == true.


Why only SQL Server?

GO is a SQL Server–specific batch separator understood by tools like sqlcmd and SSMS, not by the SQL Server engine itself. Other EF Core providers do not support or recognize GO, so the issue and fix are scoped to the SQL Server provider only.


What changed?

  • Updated SQL Server migration script generation logic to respect isScript
  • Added a functional test covering GO and GO <count> behavior in script migrations

Tests

  • Script_migration_does_not_treat_GO_as_batch_delimiter

Behavior Before

CREATE TABLE T1 (Id int);
GO
INSERT INTO T1 VALUES (1);
GO 2
INSERT INTO T1 VALUES (2);

Was interpreted as multiple batches even in script mode, causing formatting differences and incorrect assumptions about execution behavior.

Behavior After

CREATE TABLE T1 (Id int);
GO

INSERT INTO T1 VALUES (1);
GO 2

INSERT INTO T1 VALUES (2);

GO is treated as text, not as a batch delimiter, matching SQL Server tooling expectations for scripts.

Before the Development

[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.3+b1b99bdeb3 (64-bit .NET 11.0.0-preview.2.26080.101)
[xUnit.net 00:00:03.17] Discovering: Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests
[xUnit.net 00:00:11.28] Discovered: Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests
[xUnit.net 00:00:11.34] Starting: Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests
[xUnit.net 00:00:11.95] Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGeneratorTest.Script_migration_does_not_treat_GO_as_batch_delimiter [FAIL]
[xUnit.net 00:00:11.95] Assert.Equal() Failure: Strings differ
[xUnit.net 00:00:11.95] ↓ (pos 63)
[xUnit.net 00:00:11.95] Expected: ···"O T1 VALUES (1);\r\nGO 2\r\n\r\nINSERT INTO T1 "···
[xUnit.net 00:00:11.95] Actual: ···"O T1 VALUES (1);\r\nGO\r\n\r\nINSERT INTO T1 VA"···
[xUnit.net 00:00:11.95] ↑ (pos 63)
[xUnit.net 00:00:11.96] Stack Trace:
[xUnit.net 00:00:11.96] C:\Projects\efcore\test\EFCore.Relational.Specification.Tests\Migrations\MigrationsSqlGeneratorTestBase.cs(777,0): at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGeneratorTestBase.AssertSql(String expected)
[xUnit.net 00:00:11.96] C:\Projects\efcore\test\EFCore.SqlServer.FunctionalTests\Migrations\SqlServerMigrationsSqlGeneratorTest.cs(1823,0): at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGeneratorTest.Script_migration_does_not_treat_GO_as_batch_delimiter()
[xUnit.net 00:00:11.96] at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
[xUnit.net 00:00:11.96] at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
[xUnit.net 00:00:11.96] at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
[xUnit.net 00:00:11.96] Finished: Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests
EFCore.SqlServer.FunctionalTests test net11.0 failed with 1 error(s) (14.2s)
C:\Projects\efcore\test\EFCore.Relational.Specification.Tests\Migrations\MigrationsSqlGeneratorTestBase.cs(777): error TESTERROR:
Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGeneratorTest.Script_migration_does_not_treat_GO_as
_batch_delimiter (551ms): Error Message: Assert.Equal() Failure: Strings differ
↓ (pos 63)
Expected: ···"O T1 VALUES (1);\r\nGO 2\r\n\r\nINSERT INTO T1 "···
Actual: ···"O T1 VALUES (1);\r\nGO\r\n\r\nINSERT INTO T1 VA"···
↑ (pos 63)
Stack Trace:
at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGeneratorTestBase.AssertSql(String expected) in C:\Pro
jects\efcore\test\EFCore.Relational.Specification.Tests\Migrations\MigrationsSqlGeneratorTestBase.cs:line 777
at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGeneratorTest.Script_migration_does_not_treat
_GO_as_batch_delimiter() in C:\Projects\efcore\test\EFCore.SqlServer.FunctionalTests\Migrations\SqlServerMigration
sSqlGeneratorTest.cs:line 1823
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack si
g, BOOL isConstructor, ObjectHandleOnStack result)
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] para
meters, CultureInfo culture)

Test summary: total: 1, failed: 1, succeeded: 0, skipped: 0, duration: 14.1s
Build failed with 1 error(s) in 62.2s

Fixes #37628

@BurakBebek1 BurakBebek1 requested a review from a team as a code owner February 5, 2026 13:49
@roji
Copy link
Member

roji commented Feb 5, 2026

Am not sure exactly how this relates to e.g. #37521, but the parser here definitely seems insufficient (e.g. when GO is within a string). @AndriySvyryd assigning to you as I think you have more knowledge in what we're doing in this area.

@BurakBebek1
Copy link
Author

Hi @roji @AndriySvyryd , thanks for the feedback!

I’d like to clarify the scope of this PR:

This PR fixes script migrations for SQL Server:

GO and GO lines are now preserved as text when MigrationsSqlGenerationOptions.Script is used.

Previously, script mode incorrectly split GO into multiple batches, causing errors for commands like CREATE VIEW.

Normal migration batch parsing is unchanged; other edge cases (e.g., GO in strings or comments) are out of scope.

Test added: Script_migration_does_not_treat_GO_as_batch_delimiter.

Only SQL Server is affected, since GO is a SQL Server–specific batch separator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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.

3 participants