diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs index 3fa8cd4ab0..dcf18527e7 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs @@ -65,7 +65,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial return new Version(4, 7, 0); } - return new Version(4, 9, 0); + return new Version(4, 8, 0); } //if the error is for umbracoServer diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs index f49bea5ce0..b42b4aa6b8 100644 --- a/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs @@ -16,8 +16,21 @@ namespace Umbraco.Core.Persistence.Migrations ProductName = product; } + public MigrationAttribute(string minimumCurrentVersion, string targetVersion, int sortOrder, string product) + { + TargetVersion = new Version(targetVersion); + MinimumCurrentVersion = new Version(minimumCurrentVersion); + SortOrder = sortOrder; + ProductName = product; + } + /// - /// Gets or sets the target version of this migration. + /// Gets the minimum current version for which this migration is allowed to execute + /// + public Version MinimumCurrentVersion { get; private set; } + + /// + /// Gets the target version of this migration. /// public Version TargetVersion { get; private set; } diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs index 9bc9cd8e9c..5823c70e79 100644 --- a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs @@ -13,13 +13,13 @@ namespace Umbraco.Core.Persistence.Migrations /// public class MigrationRunner { - private readonly Version _configuredVersion; + private readonly Version _currentVersion; private readonly Version _targetVersion; private readonly string _productName; - public MigrationRunner(Version configuredVersion, Version targetVersion, string productName) + public MigrationRunner(Version currentVersion, Version targetVersion, string productName) { - _configuredVersion = configuredVersion; + _currentVersion = currentVersion; _targetVersion = targetVersion; _productName = productName; } @@ -46,20 +46,20 @@ namespace Umbraco.Core.Persistence.Migrations { LogHelper.Info("Initializing database migrations"); - var foundMigrations = MigrationResolver.Current.Migrations.ToArray(); + var foundMigrations = MigrationResolver.Current.Migrations.ToArray(); //filter all non-schema migrations var migrations = isUpgrade ? OrderedUpgradeMigrations(foundMigrations).ToList() : OrderedDowngradeMigrations(foundMigrations).ToList(); - + //SD: Why do we want this? - if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _configuredVersion, _targetVersion, true), this)) + if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _currentVersion, _targetVersion, true), this)) return false; //Loop through migrations to generate sql var migrationContext = InitializeMigrations(migrations, database, databaseProvider, isUpgrade); - + try { ExecuteMigrations(migrationContext, database); @@ -81,13 +81,13 @@ namespace Umbraco.Core.Persistence.Migrations throw; } - Migrated.RaiseEvent(new MigrationEventArgs(migrations, migrationContext, _configuredVersion, _targetVersion, false), this); + Migrated.RaiseEvent(new MigrationEventArgs(migrations, migrationContext, _currentVersion, _targetVersion, false), this); return true; } - private void ExecuteMigrations(IMigrationContext context, Database database) - { + private void ExecuteMigrations(IMigrationContext context, Database database) + { //Transactional execution of the sql that was generated from the found migrations using (var transaction = database.GetTransaction()) { @@ -108,13 +108,13 @@ namespace Umbraco.Core.Persistence.Migrations transaction.Complete(); } - } + } internal MigrationContext InitializeMigrations(List migrations, Database database, DatabaseProviders databaseProvider, bool isUpgrade = true) - { + { //Loop through migrations to generate sql var context = new MigrationContext(databaseProvider, database); - + foreach (var migration in migrations) { var baseMigration = migration as MigrationBase; @@ -148,35 +148,49 @@ namespace Umbraco.Core.Persistence.Migrations } return context; - } + } + /// + /// Filters and orders migrations based on the migrations listed and the currently configured version and the target installation version + /// + /// + /// internal IEnumerable OrderedUpgradeMigrations(IEnumerable foundMigrations) { var migrations = (from migration in foundMigrations - let migrationAttributes = migration.GetType().GetCustomAttributes(false) - from migrationAttribute in migrationAttributes - where migrationAttribute != null - where - migrationAttribute.TargetVersion > _configuredVersion && - migrationAttribute.TargetVersion <= _targetVersion && - migrationAttribute.ProductName == _productName - orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder ascending - select migration).Distinct(); + let migrationAttributes = migration.GetType().GetCustomAttributes(false) + from migrationAttribute in migrationAttributes + where migrationAttribute != null + where + migrationAttribute.TargetVersion > _currentVersion && + migrationAttribute.TargetVersion <= _targetVersion && + migrationAttribute.ProductName == _productName && + //filter if the migration specifies a minimum current version for which to execute + (migrationAttribute.MinimumCurrentVersion == null || _currentVersion >= migrationAttribute.MinimumCurrentVersion) + orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder ascending + select migration).Distinct(); return migrations; } + /// + /// Filters and orders migrations based on the migrations listed and the currently configured version and the target installation version + /// + /// + /// public IEnumerable OrderedDowngradeMigrations(IEnumerable foundMigrations) { var migrations = (from migration in foundMigrations - let migrationAttributes = migration.GetType().GetCustomAttributes(false) - from migrationAttribute in migrationAttributes - where migrationAttribute != null - where - migrationAttribute.TargetVersion > _configuredVersion && - migrationAttribute.TargetVersion <= _targetVersion && - migrationAttribute.ProductName == _productName - orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder descending - select migration).Distinct(); + let migrationAttributes = migration.GetType().GetCustomAttributes(false) + from migrationAttribute in migrationAttributes + where migrationAttribute != null + where + migrationAttribute.TargetVersion > _currentVersion && + migrationAttribute.TargetVersion <= _targetVersion && + migrationAttribute.ProductName == _productName && + //filter if the migration specifies a minimum current version for which to execute + (migrationAttribute.MinimumCurrentVersion == null || _currentVersion >= migrationAttribute.MinimumCurrentVersion) + orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder descending + select migration).Distinct(); return migrations; } diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys.cs index a4fae3ae83..7c7bbf54fb 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero { + //see: http://issues.umbraco.org/issue/U4-4430 [Migration("6.2.0", 0, GlobalSettings.UmbracoMigrationName)] public class AssignMissingPrimaryForMySqlKeys : MigrationBase @@ -14,15 +15,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero if (Context.CurrentDatabaseProvider == DatabaseProviders.MySql) { var constraints = SqlSyntaxContext.SqlSyntaxProvider.GetConstraintsPerColumn(Context.Database).Distinct().ToArray(); - - //This should be 2 because this table has 2 keys - if (constraints.Count(x => x.Item1.InvariantEquals("cmsContentType2ContentType") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_cmsContentType2ContentType") - .OnTable("cmsContentType2ContentType") - .Columns(new[] {"parentContentTypeId", "childContentTypeId"}); - } - + //This should be 2 because this table has 2 keys if (constraints.Count(x => x.Item1.InvariantEquals("cmsContentTypeAllowedContentType") && x.Item3.InvariantEquals("PRIMARY")) == 0) { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys2.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys2.cs new file mode 100644 index 0000000000..65e440a1da --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys2.cs @@ -0,0 +1,34 @@ +using System.Linq; +using Umbraco.Core.Configuration; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero +{ + //We have to target this specifically to ensure this DOES NOT execute if upgrading from a version previous to 6.0, + // this is because when the 6.0.0 migrations are executed, this primary key get's created so if this migration is also executed + // we will get exceptions because it is trying to create the PK two times. + [Migration("6.0.0", "6.2.0", 0, GlobalSettings.UmbracoMigrationName)] + public class AssignMissingPrimaryForMySqlKeys2 : MigrationBase + { + public override void Up() + { + if (Context.CurrentDatabaseProvider == DatabaseProviders.MySql) + { + var constraints = SqlSyntaxContext.SqlSyntaxProvider.GetConstraintsPerColumn(Context.Database).Distinct().ToArray(); + + //This should be 2 because this table has 2 keys + if (constraints.Count(x => x.Item1.InvariantEquals("cmsContentType2ContentType") && x.Item3.InvariantEquals("PRIMARY")) == 0) + { + Create.PrimaryKey("PK_cmsContentType2ContentType") + .OnTable("cmsContentType2ContentType") + .Columns(new[] {"parentContentTypeId", "childContentTypeId"}); + } + } + } + + public override void Down() + { + //don't do anything, these keys should have always existed! + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 7169cc09ae..18be6898de 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -228,6 +228,7 @@ + diff --git a/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs b/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs index dd28e559bb..d7aca12bfa 100644 --- a/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs @@ -16,7 +16,7 @@ namespace Umbraco.Tests.Migrations { var runner = new MigrationRunner(new Version(4, 0, 0), new Version(6, 0, 0), "Test"); - var migrations = runner.OrderedUpgradeMigrations(new List {new MultiMigration()}); + var migrations = runner.OrderedUpgradeMigrations(new List { new MultiMigration() }); var ctx = runner.InitializeMigrations( //new List {new DoRunMigration(), new DoNotRunMigration()}, @@ -58,7 +58,7 @@ namespace Umbraco.Tests.Migrations Assert.AreEqual(1, ctx.Expressions.Count()); } - + [Migration("6.0.0", 1, "Test")] [Migration("5.0.0", 1, "Test")] private class MultiMigration : MigrationBase