diff --git a/src/Libraries/Nop.Data/Extensions/FluentMigratorExtensions.cs b/src/Libraries/Nop.Data/Extensions/FluentMigratorExtensions.cs index 81f9d6f88f8..ea2bbfcb572 100644 --- a/src/Libraries/Nop.Data/Extensions/FluentMigratorExtensions.cs +++ b/src/Libraries/Nop.Data/Extensions/FluentMigratorExtensions.cs @@ -1,9 +1,17 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Data; +using System.Linq.Expressions; using System.Reflection; +using FluentMigrator.Builders; +using FluentMigrator.Builders.Alter; using FluentMigrator.Builders.Alter.Table; using FluentMigrator.Builders.Create; using FluentMigrator.Builders.Create.Table; +using FluentMigrator.Builders.Delete; +using FluentMigrator.Builders.Delete.Column; +using FluentMigrator.Builders.Schema; +using FluentMigrator.Builders.Schema.Column; +using FluentMigrator.Builders.Schema.Table; using FluentMigrator.Infrastructure.Extensions; using FluentMigrator.Model; using FluentMigrator.Runner; @@ -63,7 +71,7 @@ private static void DefineByOwnType(string columnName, Type propType, CreateTabl /// The builder to add the database engine(s) to /// The migration runner builder public static IMigrationRunnerBuilder AddNopDbEngines(this IMigrationRunnerBuilder builder) - { + { if (!DataSettingsManager.IsDatabaseInstalled()) return builder.AddSqlServer().AddMySql5().AddPostgres92(); @@ -145,6 +153,101 @@ public static void TableFor(this ICreateExpressionRoot expressionRoot) builder.RetrieveTableExpressions(type); } + /// + /// Targets the entity's mapped table for a DELETE operation. + /// + /// The root expression for a DELETE operation + /// The entity type mapped to the database table + public static void TableFor(this IDeleteExpressionRoot expressionRoot) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + expressionRoot.Table(tableName); + } + + /// + /// Targets the entity's mapped table for an ALTER TABLE operation. + /// + /// The root expression for an ALTER operation + /// The entity type mapped to the database table + /// + /// A fluent syntax interface allowing further ALTER TABLE operations + /// such as adding or modifying columns. + /// + public static IAlterTableAddColumnOrAlterColumnOrSchemaOrDescriptionSyntax TableFor(this IAlterExpressionRoot expressionRoot) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + return expressionRoot.Table(tableName); + } + + /// + /// Targets the entity's mapped table for schema-related operations. + /// + /// The root expression for schema inspection + /// The entity type mapped to the database table + /// + /// A fluent syntax interface for performing schema operations + /// such as checking table or column existence. + /// + public static ISchemaTableSyntax TableFor(this ISchemaExpressionRoot expressionRoot) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + return expressionRoot.Table(tableName); + } + + /// + /// Targets a specific column of the entity's mapped table for schema inspection, + /// resolving the column name via . + /// + /// The entity type mapped to the database table + /// The schema table expression + /// An expression selecting the entity property + /// + /// A fluent syntax interface for performing schema operations + /// such as checking column existence. + /// + public static ISchemaColumnSyntax ColumnFor( + this ISchemaTableSyntax tableSchema, Expression> selector) where TEntity : BaseEntity + { + var property = ((MemberExpression)selector.Body)?.Member?.Name; + var columnName = NameCompatibilityManager.GetColumnName(typeof(TEntity), property!); + return tableSchema.Column(columnName); + } + + /// + /// Adds a new column to the entity's mapped table for ALTER TABLE operations, + /// resolving the column name via . + /// + /// The entity type mapped to the database table + /// The alter table expression + /// An expression selecting the entity property + /// + /// A fluent syntax interface allowing further ALTER TABLE operations + /// on the specified column. + /// + public static IAlterTableColumnAsTypeSyntax AddColumnFor( + this IAlterTableAddColumnOrAlterColumnSyntax tableSchema, Expression> selector) where TEntity : BaseEntity + { + var property = ((MemberExpression)selector.Body)?.Member?.Name; + var columnName = NameCompatibilityManager.GetColumnName(typeof(TEntity), property!); + return tableSchema.AddColumn(columnName); + } + + /// + /// Targets the mapped table of the specified entity for a DELETE COLUMN operation, + /// resolving the table name via . + /// + /// The entity type mapped to the database table + /// The delete column expression from table syntax + /// + /// A fluent syntax interface allowing the deletion of columns from the specified table. + /// + public static IInSchemaSyntax FromTable( + this IDeleteColumnFromTableSyntax expressionRoot) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + return expressionRoot.FromTable(tableName); + } + /// /// Retrieves expressions for building an entity table /// diff --git a/src/Libraries/Nop.Data/Migrations/UpgradeTo490/SchemaMigration.cs b/src/Libraries/Nop.Data/Migrations/UpgradeTo490/SchemaMigration.cs index 3e12547f59e..ab78faf6cd8 100644 --- a/src/Libraries/Nop.Data/Migrations/UpgradeTo490/SchemaMigration.cs +++ b/src/Libraries/Nop.Data/Migrations/UpgradeTo490/SchemaMigration.cs @@ -15,89 +15,93 @@ public class SchemaMigration : ForwardOnlyMigration public override void Up() { //#7387 - var productTableName = nameof(Product); - - var ageVerificationColumnName = nameof(Product.AgeVerification); - if (!Schema.Table(productTableName).Column(ageVerificationColumnName).Exists()) + if (!Schema.TableFor().ColumnFor(t => t.AgeVerification).Exists()) { - Alter.Table(productTableName) - .AddColumn(ageVerificationColumnName) + Alter.TableFor() + .AddColumnFor(t => t.AgeVerification) .AsBoolean() .NotNullable() .WithDefaultValue(false); } - var minimumAgeToPurchaseColumnName = nameof(Product.MinimumAgeToPurchase); - if (!Schema.Table(productTableName).Column(minimumAgeToPurchaseColumnName).Exists()) + if (!Schema.TableFor().ColumnFor(t => t.MinimumAgeToPurchase).Exists()) { - Alter.Table(productTableName) - .AddColumn(minimumAgeToPurchaseColumnName) + Alter.TableFor() + .AddColumnFor(t => t.MinimumAgeToPurchase) .AsInt32() .NotNullable() .WithDefaultValue(0); } //#7294 - var topicTableName = nameof(Topic); - var topicAvailableEndDateColumnName = nameof(Topic.AvailableEndDateTimeUtc); - var topicAvailableStartDateColumnName = nameof(Topic.AvailableStartDateTimeUtc); - if (!Schema.Table(topicTableName).Column(topicAvailableEndDateColumnName).Exists()) + if (!Schema.TableFor().ColumnFor(t => t.AvailableEndDateTimeUtc).Exists()) { - Alter.Table(topicTableName) - .AddColumn(topicAvailableEndDateColumnName) + Alter.TableFor() + .AddColumnFor(t => t.AvailableEndDateTimeUtc) .AsDateTime() .Nullable(); } - if (!Schema.Table(topicTableName).Column(topicAvailableStartDateColumnName).Exists()) + if (!Schema.TableFor().ColumnFor(t => t.AvailableStartDateTimeUtc).Exists()) { - Alter.Table(topicTableName) - .AddColumn(topicAvailableStartDateColumnName) + Alter.TableFor() + .AddColumnFor(t => t.AvailableStartDateTimeUtc) .AsDateTime() .Nullable(); } //#873 - var productTagTableName = nameof(ProductTag); - if (!Schema.Table(productTagTableName).Column(nameof(ProductTag.MetaDescription)).Exists()) - Alter.Table(productTagTableName).AddColumn(nameof(ProductTag.MetaDescription)).AsString().Nullable(); + if (!Schema.TableFor().ColumnFor(t => t.MetaDescription).Exists()) + { + Alter.TableFor() + .AddColumnFor(t => t.MetaDescription) + .AsString() + .Nullable(); + } - if (!Schema.Table(productTagTableName).Column(nameof(ProductTag.MetaKeywords)).Exists()) - Alter.Table(productTagTableName).AddColumn(nameof(ProductTag.MetaKeywords)).AsString(400).Nullable(); + if (!Schema.TableFor().ColumnFor(t => t.MetaKeywords).Exists()) + { + Alter.TableFor() + .AddColumnFor(t => t.MetaKeywords) + .AsString(400) + .Nullable(); + } - if (!Schema.Table(productTagTableName).Column(nameof(ProductTag.MetaTitle)).Exists()) - Alter.Table(productTagTableName).AddColumn(nameof(ProductTag.MetaTitle)).AsString(400).Nullable(); + if (!Schema.TableFor().ColumnFor(t => t.MetaTitle).Exists()) + { + Alter.TableFor() + .AddColumnFor(t => t.MetaTitle) + .AsString(400) + .Nullable(); + } //#7390 - if (!Schema.Table(nameof(Menu)).Exists()) + if (!Schema.TableFor().Exists()) Create.TableFor(); - if (!Schema.Table(nameof(MenuItem)).Exists()) + if (!Schema.TableFor().Exists()) Create.TableFor(); var footerColumn1ColumnName = "IncludeInFooterColumn1"; - if (Schema.Table(topicTableName).Column(footerColumn1ColumnName).Exists()) - Delete.Column(footerColumn1ColumnName).FromTable(topicTableName); + if (Schema.TableFor().Column(footerColumn1ColumnName).Exists()) + Delete.Column(footerColumn1ColumnName).FromTable(); var footerColumn2ColumnName = "IncludeInFooterColumn2"; - if (Schema.Table(topicTableName).Column(footerColumn2ColumnName).Exists()) - Delete.Column(footerColumn2ColumnName).FromTable(topicTableName); + if (Schema.TableFor().Column(footerColumn2ColumnName).Exists()) + Delete.Column(footerColumn2ColumnName).FromTable(); var footerColumn3ColumnName = "IncludeInFooterColumn3"; - if (Schema.Table(topicTableName).Column(footerColumn3ColumnName).Exists()) - Delete.Column(footerColumn3ColumnName).FromTable(topicTableName); + if (Schema.TableFor().Column(footerColumn3ColumnName).Exists()) + Delete.Column(footerColumn3ColumnName).FromTable(); var includeTopicInTopMenuColumnName = "IncludeInTopMenu"; - if (Schema.Table(topicTableName).Column(includeTopicInTopMenuColumnName).Exists()) - Delete.Column(includeTopicInTopMenuColumnName).FromTable(topicTableName); + if (Schema.TableFor().Column(includeTopicInTopMenuColumnName).Exists()) + Delete.Column(includeTopicInTopMenuColumnName).FromTable(); - var categoryTableName = nameof(Category); var includeCategoryInTopMenuColumnName = "IncludeInTopMenu"; - if (Schema.Table(categoryTableName).Column(includeCategoryInTopMenuColumnName).Exists()) - Delete.Column(includeCategoryInTopMenuColumnName).FromTable(categoryTableName); - - + if (Schema.TableFor().Column(includeCategoryInTopMenuColumnName).Exists()) + Delete.Column(includeCategoryInTopMenuColumnName).FromTable(); } }