diff --git a/src/Libraries/Nop.Data/Extensions/FluentMigratorExtensions.cs b/src/Libraries/Nop.Data/Extensions/FluentMigratorExtensions.cs index 81f9d6f88f8..7c999b4e8b6 100644 --- a/src/Libraries/Nop.Data/Extensions/FluentMigratorExtensions.cs +++ b/src/Libraries/Nop.Data/Extensions/FluentMigratorExtensions.cs @@ -1,9 +1,13 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Data; +using System.Linq.Expressions; using System.Reflection; +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.Schema; using FluentMigrator.Infrastructure.Extensions; using FluentMigrator.Model; using FluentMigrator.Runner; @@ -63,7 +67,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 +149,88 @@ public static void TableFor(this ICreateExpressionRoot expressionRoot) builder.RetrieveTableExpressions(type); } + /// + /// Deletes a column from the table mapped to the specified entity, + /// resolving the table name using . + /// + /// The entity type mapped to the database table. + /// The root delete expression. + /// The name of the column to delete. + public static void Column(this IDeleteExpressionRoot expressionRoot, string columnName) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + expressionRoot.Column(columnName).FromTable(tableName); + } + + /// + /// Determines whether the database table mapped to the specified entity exists, + /// resolving the table name using . + /// + /// The entity type mapped to the database table. + /// The root schema expression. + /// true if the table exists; otherwise, false. + public static bool TableExist(this ISchemaExpressionRoot expressionRoot) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + return expressionRoot.Table(tableName).Exists(); + } + + /// + /// Checks whether a mapped column exists in the database table for the specified entity. + /// Resolves both the table name and column name using . + /// + /// The entity type mapped to the database table. + /// The root schema expression. + /// An expression selecting the entity property to check. + /// true if the column exists; otherwise, false. + public static bool ColumnExist( + this ISchemaExpressionRoot expressionRoot, Expression> selector) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + var propertyMemberExpression = selector.Body as MemberExpression + ?? (selector.Body as UnaryExpression)?.Operand as MemberExpression + ?? throw new ArgumentException("Selector must be a property expression.", nameof(selector)); + var columnName = NameCompatibilityManager.GetColumnName(typeof(TEntity), propertyMemberExpression.Member.Name); + return expressionRoot.Table(tableName).Column(columnName).Exists(); + } + + /// + /// Checks whether a mapped column exists in the database table for the specified entity. + /// Resolves both the table name and column name using . + /// + /// The entity type mapped to the database table. + /// The root schema expression. + /// The column name + /// true if the column exists; otherwise, false. + public static bool ColumnExist( + this ISchemaExpressionRoot expressionRoot, string columnName) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + return expressionRoot.Table(tableName).Column(columnName).Exists(); + } + + /// + /// 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 IAlterExpressionRoot expressionRoot, Expression> selector) where TEntity : BaseEntity + { + var tableName = NameCompatibilityManager.GetTableName(typeof(TEntity)); + var propertyMemberExpression = selector.Body as MemberExpression + ?? (selector.Body as UnaryExpression)?.Operand as MemberExpression + ?? throw new ArgumentException("Selector must be a property expression.", nameof(selector)); + var columnName = NameCompatibilityManager.GetColumnName(typeof(TEntity), propertyMemberExpression.Member.Name); + return expressionRoot.Table(tableName).AddColumn(columnName); + } + /// /// 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..4e9af08a18d 100644 --- a/src/Libraries/Nop.Data/Migrations/UpgradeTo490/SchemaMigration.cs +++ b/src/Libraries/Nop.Data/Migrations/UpgradeTo490/SchemaMigration.cs @@ -15,89 +15,86 @@ 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.ColumnExist(t => t.AgeVerification)) { - Alter.Table(productTableName) - .AddColumn(ageVerificationColumnName) + Alter.AddColumnFor(t => t.AgeVerification) .AsBoolean() .NotNullable() .WithDefaultValue(false); } - var minimumAgeToPurchaseColumnName = nameof(Product.MinimumAgeToPurchase); - if (!Schema.Table(productTableName).Column(minimumAgeToPurchaseColumnName).Exists()) + if (!Schema.ColumnExist(t => t.MinimumAgeToPurchase)) { - Alter.Table(productTableName) - .AddColumn(minimumAgeToPurchaseColumnName) + Alter.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.ColumnExist(t => t.AvailableEndDateTimeUtc)) { - Alter.Table(topicTableName) - .AddColumn(topicAvailableEndDateColumnName) + Alter.AddColumnFor(t => t.AvailableEndDateTimeUtc) .AsDateTime() .Nullable(); } - if (!Schema.Table(topicTableName).Column(topicAvailableStartDateColumnName).Exists()) + if (!Schema.ColumnExist(t => t.AvailableStartDateTimeUtc)) { - Alter.Table(topicTableName) - .AddColumn(topicAvailableStartDateColumnName) + Alter.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.ColumnExist(t => t.MetaDescription)) + { + Alter.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.ColumnExist(t => t.MetaKeywords)) + { + Alter.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.ColumnExist(t => t.MetaTitle)) + { + Alter.AddColumnFor(t => t.MetaTitle) + .AsString(400) + .Nullable(); + } //#7390 - if (!Schema.Table(nameof(Menu)).Exists()) + if (!Schema.TableExist()) Create.TableFor(); - if (!Schema.Table(nameof(MenuItem)).Exists()) + if (!Schema.TableExist()) Create.TableFor(); var footerColumn1ColumnName = "IncludeInFooterColumn1"; - if (Schema.Table(topicTableName).Column(footerColumn1ColumnName).Exists()) - Delete.Column(footerColumn1ColumnName).FromTable(topicTableName); + if (Schema.ColumnExist(footerColumn1ColumnName)) + Delete.Column(footerColumn1ColumnName); var footerColumn2ColumnName = "IncludeInFooterColumn2"; - if (Schema.Table(topicTableName).Column(footerColumn2ColumnName).Exists()) - Delete.Column(footerColumn2ColumnName).FromTable(topicTableName); + if (Schema.ColumnExist(footerColumn2ColumnName)) + Delete.Column(footerColumn2ColumnName); var footerColumn3ColumnName = "IncludeInFooterColumn3"; - if (Schema.Table(topicTableName).Column(footerColumn3ColumnName).Exists()) - Delete.Column(footerColumn3ColumnName).FromTable(topicTableName); + if (Schema.ColumnExist(footerColumn3ColumnName)) + Delete.Column(footerColumn3ColumnName); var includeTopicInTopMenuColumnName = "IncludeInTopMenu"; - if (Schema.Table(topicTableName).Column(includeTopicInTopMenuColumnName).Exists()) - Delete.Column(includeTopicInTopMenuColumnName).FromTable(topicTableName); + if (Schema.ColumnExist(includeTopicInTopMenuColumnName)) + Delete.Column(includeTopicInTopMenuColumnName); - var categoryTableName = nameof(Category); var includeCategoryInTopMenuColumnName = "IncludeInTopMenu"; - if (Schema.Table(categoryTableName).Column(includeCategoryInTopMenuColumnName).Exists()) - Delete.Column(includeCategoryInTopMenuColumnName).FromTable(categoryTableName); - - + if (Schema.ColumnExist(includeCategoryInTopMenuColumnName)) + Delete.Column(includeCategoryInTopMenuColumnName); } }