Inconsistent versioned table management in migrations
- Dominant language
- C#
- Stars
- 14.8k
- Forks
- 3.4k
- PR merge metrics
- PR metrics pending
Description
### Bug description
Hi! I noticed when using a custom script in a migration that the management of the temporal versioning is inconsistent and unexpected, at least to me
If there's a change to a versioned-table's schema in the migration, it seems that the generated migration:
1. Turns off versioning the first time it encounters a schema change to a temporally managed table.
2. Wraps the rest of the migration script in that transaction/de-versioned time.
3. Re-enables the versioning as the last act of the migration script.
If there's no change to a versioned-table's schema in the migration, the generated migration doesn't turn off/on versioning at all.
The result is very inconsistent version management when using custom SQL and can easily result in unexpected data management. For example, if the custom script is **before** a versioned table's schema changes, the updates would be captured by versioning. If the custom script is **anywhere after** a change to a versioned table's schema, the updates **would not** be captured by versioning (i.e., nothing would be added to the associated XXXHistory table.
Below you can see the inconsistent (or at least very unexpected to me) versioning results with custom scripting:
Personally, I wouldn't expect the location of the custom script to impact data storage. And while I'm assuming the reason for leaving the versioning off until the end of the script is to avoid the back and forth of versioning off/on multiple times, I wouldn't expect any custom script to be "wrapped" in an unversioned transaction unless I specifically write it that way.
Happy to help with this however I can - thanks!
### Your code
```csharp
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("UPDATE [Inspection] SET [Notes] = 'Versioned'");
migrationBuilder.DropColumn(
name: "County",
table: "InspectionZone");
migrationBuilder.Sql("UPDATE [Inspection] SET [Notes] = 'Again Versioned'");
migrationBuilder.DropColumn(
name: "Inspector",
table: "Inspection");
migrationBuilder.Sql("UPDATE [Inspection] SET [Notes] = 'Unversioned'");
}
..produces..
BEGIN TRANSACTION;
UPDATE [Inspection] SET [Notes] = 'Versioned'
DECLARE @var1 sysname;
SELECT @var1 = [d].[name]
FROM [sys].[default_constraints] [d]
INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
WHERE ([d].[parent_object_id] = OBJECT_ID(N'[InspectionZone]') AND [c].[name] = N'County');
IF @var1 IS NOT NULL EXEC(N'ALTER TABLE [InspectionZone] DROP CONSTRAINT [' + @var1 + '];');
ALTER TABLE [InspectionZone] DROP COLUMN [County];
UPDATE [Inspection] SET [Notes] = 'Again Versioned'
ALTER TABLE [Inspection] SET (SYSTEM_VERSIONING = OFF)
DECLARE @var2 sysname;
SELECT @var2 = [d].[name]
FROM [sys].[default_constraints] [d]
INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
WHERE ([d].[parent_object_id] = OBJECT_ID(N'[Inspection]') AND [c].[name] = N'Inspector');
IF @var2 IS NOT NULL EXEC(N'ALTER TABLE [Inspection] DROP CONSTRAINT [' + @var2 + '];');
ALTER TABLE [Inspection] DROP COLUMN [Inspector];
DECLARE @var3 sysname;
SELECT @var3 = [d].[name]
FROM [sys].[default_constraints] [d]
INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id]
WHERE ([d].[parent_object_id] = OBJECT_ID(N'[InspectionHistory]') AND [c].[name] = N'Inspector');
IF @var3 IS NOT NULL EXEC(N'ALTER TABLE [InspectionHistory] DROP CONSTRAINT [' + @var3 + '];');
ALTER TABLE [InspectionHistory] DROP COLUMN [Inspector];
UPDATE [Inspection] SET [Notes] = 'Unversioned'
DECLARE @historyTableSchema sysname = SCHEMA_NAME()
EXEC(N'ALTER TABLE [Inspection] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [' + @historyTableSchema + '].[InspectionHistory]))')
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20250428192026_CustomScriptVersioning', N'9.0.4');
COMMIT;
GO
```
### EF Core version
9.0.4
### Database provider
Microsoft.EntityFrameworkCore.SqlServer
### Target framework
NET9
### Operating system
Windows 10
### IDE
Visual Studio Professional 17.13.3
Contributor guide
Assessment
This issue has not been assessed yet.