From 822a2fcf70ec34d7613bd7ad7f89c08ebacb94a2 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 1 Dec 2025 19:01:55 +0100 Subject: [PATCH] Migrations: Ensure `umbracoPropertyData` column casing (#21015) * Add migration to fix umbracoPropertyData column casing. * Improve migration with column existence check and logging - Add ILogger to log when column is renamed - Check if column exists with incorrect casing before renaming - Use fluent Rename API instead of raw SQL - Add XML remarks documentation ?? Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude * Clarify what old and new column name really is --------- Co-authored-by: Claude Co-authored-by: kjac # Conflicts: # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs --- .../Migrations/Upgrade/UmbracoPlan.cs | 3 ++ .../EnsureUmbracoPropertyDataColumnCasing.cs | 54 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/Umbraco.Infrastructure/Migrations/Upgrade/V_17_0_1/EnsureUmbracoPropertyDataColumnCasing.cs diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index 599f8367e4..ac16a57ea7 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -140,5 +140,8 @@ public class UmbracoPlan : MigrationPlan To("26179D88-58CE-4C92-B4A4-3CBA6E7188AC"); To("{8B2C830A-4FFB-4433-8337-8649B0BF52C8}"); To("{1C38D589-26BB-4A46-9ABE-E4A0DF548A87}"); + + // To 17.0.1 + To("{BE5CA411-E12D-4455-A59E-F12A669E5363}"); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_17_0_1/EnsureUmbracoPropertyDataColumnCasing.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_17_0_1/EnsureUmbracoPropertyDataColumnCasing.cs new file mode 100644 index 0000000000..6c97c075dd --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_17_0_1/EnsureUmbracoPropertyDataColumnCasing.cs @@ -0,0 +1,54 @@ +using Microsoft.Extensions.Logging; +using NPoco; +using static Umbraco.Cms.Core.Constants; +using ColumnInfo = Umbraco.Cms.Infrastructure.Persistence.SqlSyntax.ColumnInfo; + +namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_17_0_1; + +/// +/// Ensures the propertyTypeId column in umbracoPropertyData has correct camel case naming. +/// +/// +/// SQL Server is case sensitive for columns used in a SQL Bulk insert statement (which is used in publishing +/// operations on umbracoPropertyData). +/// Earlier versions of Umbraco used all lower case for the propertyTypeId column name (propertytypeid), whereas newer versions +/// use camel case (propertyTypeId). +/// +public class EnsureUmbracoPropertyDataColumnCasing : AsyncMigrationBase +{ + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public EnsureUmbracoPropertyDataColumnCasing(IMigrationContext context, ILogger logger) + : base(context) => _logger = logger; + + /// + protected override Task MigrateAsync() + { + // We only need to do this for SQL Server. + if (DatabaseType == DatabaseType.SQLite) + { + return Task.CompletedTask; + } + + const string oldColumnName = "propertytypeid"; + const string newColumnName = "propertyTypeId"; + ColumnInfo[] columns = [.. SqlSyntax.GetColumnsInSchema(Context.Database)]; + ColumnInfo? targetColumn = columns + .FirstOrDefault(x => x.TableName == DatabaseSchema.Tables.PropertyData && string.Equals(x.ColumnName, oldColumnName, StringComparison.InvariantCulture)); + if (targetColumn is not null) + { + // The column exists with incorrect casing, we need to rename it. + Rename.Column(oldColumnName) + .OnTable(DatabaseSchema.Tables.PropertyData) + .To(newColumnName) + .Do(); + + _logger.LogInformation("Renamed column {OldColumnName} to {NewColumnName} on table {TableName}", oldColumnName, newColumnName, DatabaseSchema.Tables.PropertyData); + } + + return Task.CompletedTask; + } +}