Skip to content

Commit 5077465

Browse files
committed
Fix making column required on SQL Server with idempotent migrations (dotnet#29619)
Fixes dotnet#29530 (cherry picked from commit 6b3b852)
1 parent fbc493a commit 5077465

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs

+16-3
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ protected override void Generate(
369369
defaultValueSql = typeMapping.GenerateSqlLiteral(operation.DefaultValue);
370370
}
371371

372-
builder
372+
var updateBuilder = new StringBuilder()
373373
.Append("UPDATE ")
374374
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Table, operation.Schema))
375375
.Append(" SET ")
@@ -378,8 +378,21 @@ protected override void Generate(
378378
.Append(defaultValueSql)
379379
.Append(" WHERE ")
380380
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name))
381-
.Append(" IS NULL")
382-
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
381+
.Append(" IS NULL");
382+
383+
if (Options.HasFlag(MigrationsSqlGenerationOptions.Idempotent))
384+
{
385+
builder
386+
.Append("EXEC(N'")
387+
.Append(updateBuilder.ToString().TrimEnd('\n', '\r', ';').Replace("'", "''"))
388+
.Append("')");
389+
}
390+
else
391+
{
392+
builder.Append(updateBuilder.ToString());
393+
}
394+
395+
builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
383396
}
384397

385398
if (alterStatementNeeded)

test/EFCore.Relational.Specification.Tests/Migrations/MigrationsSqlGeneratorTestBase.cs

+3
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,9 @@ protected MigrationsSqlGeneratorTestBase(
750750
ContextOptions = options;
751751
}
752752

753+
protected virtual void Generate(MigrationOperation operation, MigrationsSqlGenerationOptions options)
754+
=> Generate(null, new[] { operation }, options);
755+
753756
protected virtual void Generate(params MigrationOperation[] operation)
754757
=> Generate(null, operation);
755758

test/EFCore.SqlServer.FunctionalTests/Migrations/SqlServerMigrationsSqlGeneratorTest.cs

+35
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,41 @@ public virtual void CreateIndex_generates_exec_when_legacy_filter_and_idempotent
11801180
""");
11811181
}
11821182

1183+
[ConditionalFact]
1184+
public virtual void AlterColumn_make_required_with_idempotent()
1185+
{
1186+
Generate(
1187+
new AlterColumnOperation
1188+
{
1189+
Table = "Person",
1190+
Name = "Name",
1191+
ClrType = typeof(string),
1192+
IsNullable = false,
1193+
DefaultValue = "",
1194+
OldColumn = new AddColumnOperation
1195+
{
1196+
Table = "Person",
1197+
Name = "Name",
1198+
ClrType = typeof(string),
1199+
IsNullable = true
1200+
}
1201+
},
1202+
MigrationsSqlGenerationOptions.Idempotent);
1203+
1204+
AssertSql(
1205+
"""
1206+
DECLARE @var0 sysname;
1207+
SELECT @var0 = [d].[name]
1208+
FROM [sys].[default_constraints] [d]
1209+
INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
1210+
WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Person]') AND [c].[name] = N'Name');
1211+
IF @var0 IS NOT NULL EXEC(N'ALTER TABLE [Person] DROP CONSTRAINT [' + @var0 + '];');
1212+
EXEC(N'UPDATE [Person] SET [Name] = N'''' WHERE [Name] IS NULL');
1213+
ALTER TABLE [Person] ALTER COLUMN [Name] nvarchar(max) NOT NULL;
1214+
ALTER TABLE [Person] ADD DEFAULT N'' FOR [Name];
1215+
""");
1216+
}
1217+
11831218
private static void CreateGotModel(ModelBuilder b)
11841219
=> b.HasDefaultSchema("dbo").Entity(
11851220
"Person", pb =>

0 commit comments

Comments
 (0)