SqlServer: preserve GO statements in scripted migrations #37632
+50
−0
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
When generating script migrations on SQL Server,
GOstatements should be treated as plain SQL text rather than batch delimiters. Currently,GOandGO <count>are incorrectly split even in script mode.This PR ensures that
GOis not interpreted as a batch separator whenisScript == true.Why only SQL Server?
GOis a SQL Server–specific batch separator understood by tools likesqlcmdand SSMS, not by the SQL Server engine itself. Other EF Core providers do not support or recognizeGO, so the issue and fix are scoped to the SQL Server provider only.What changed?
isScriptGOandGO <count>behavior in script migrationsTests
Script_migration_does_not_treat_GO_as_batch_delimiterBehavior 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