U4-8361 - fixing migrations

This commit is contained in:
Stephan
2016-07-07 16:56:52 +02:00
parent 560c0fbb33
commit 6f6c7ede0a
9 changed files with 248 additions and 37 deletions

View File

@@ -42,9 +42,9 @@ namespace Umbraco.Core.Models.Rdbms
//[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRedirectUrl", ForColumns = "url, createDateUtc")]
public string Url { get; set; }
[Column("hurl")]
[Column("urlHash")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRedirectUrl", ForColumns = "hurl, contentKey, createDateUtc")]
public string Hurl { get; set; }
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRedirectUrl", ForColumns = "urlHash, contentKey, createDateUtc")]
public string UrlHash { get; set; }
}
}

View File

@@ -0,0 +1,54 @@
using System.Linq;
using System.Text;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter;
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
using Umbraco.Core.Persistence.Migrations.Syntax.Delete;
using Umbraco.Core.Persistence.Migrations.Syntax.Execute;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations
{
internal class LocalMigrationContext : MigrationContext
{
private readonly ISqlSyntaxProvider _sqlSyntax;
public LocalMigrationContext(DatabaseProviders databaseProvider, Database database, ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(databaseProvider, database, logger)
{
_sqlSyntax = sqlSyntax;
}
public IExecuteBuilder Execute
{
get { return new ExecuteBuilder(this, _sqlSyntax); }
}
public IDeleteBuilder Delete
{
get { return new DeleteBuilder(this, _sqlSyntax); }
}
public IAlterSyntaxBuilder Alter
{
get { return new AlterSyntaxBuilder(this, _sqlSyntax); }
}
public ICreateBuilder Create
{
get { return new CreateBuilder(this, _sqlSyntax); }
}
public string GetSql()
{
var sb = new StringBuilder();
foreach (var sql in Expressions.Select(x => x.Process(Database)))
{
sb.Append(sql);
sb.AppendLine();
sb.AppendLine("GO");
}
return sb.ToString();
}
}
}

View File

@@ -1,6 +1,7 @@
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero
@@ -14,24 +15,31 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZer
public override void Up()
{
// don't exeucte if the table is already there
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains("umbracoRedirectUrl")) return;
// defer, because we are making decisions based upon what's in the database
Execute.Code(MigrationCode);
}
Create.Table("umbracoRedirectUrl")
private string MigrationCode(Database database)
{
// don't execute if the table is already there
var tables = SqlSyntax.GetTablesInSchema(database).ToArray();
if (tables.InvariantContains("umbracoRedirectUrl")) return null;
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
localContext.Create.Table("umbracoRedirectUrl")
.WithColumn("id").AsInt32().Identity().PrimaryKey("PK_umbracoRedirectUrl")
.WithColumn("contentId").AsInt32().NotNullable()
.WithColumn("createDateUtc").AsDateTime().NotNullable()
.WithColumn("url").AsString(2048).NotNullable();
//Create.PrimaryKey("PK_umbracoRedirectUrl").OnTable("umbracoRedirectUrl").Columns(new[] { "id" });
localContext.Create.Index("IX_umbracoRedirectUrl")
.OnTable("umbracoRedirectUrl")
.OnColumn("url").Ascending()
.OnColumn("createDateUtc").Ascending()
.WithOptions().NonClustered();
Create.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl")
.OnColumn("url")
.Ascending()
.OnColumn("createDateUtc")
.Ascending()
.WithOptions().NonClustered();
return localContext.GetSql();
}
public override void Down()

View File

@@ -1,6 +1,10 @@
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter;
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
using Umbraco.Core.Persistence.Migrations.Syntax.Delete;
using Umbraco.Core.Persistence.Migrations.Syntax.Execute;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero
@@ -14,21 +18,37 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZer
public override void Up()
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
// defer, because we are making decisions based upon what's in the database
Execute.Code(MigrationCode);
}
private string MigrationCode(Database database)
{
var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoRedirectUrl") && x.ColumnName.InvariantEquals("contentKey")))
return;
return null;
Execute.Sql("DELETE FROM umbracoRedirectUrl"); // else cannot add non-nullable field
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
Delete.Column("contentId").FromTable("umbracoRedirectUrl");
localContext.Execute.Sql("DELETE FROM umbracoRedirectUrl"); // else cannot add non-nullable field
Alter.Table("umbracoRedirectUrl")
.AddColumn("contentKey").AsGuid().NotNullable();
localContext.Delete.Column("contentId").FromTable("umbracoRedirectUrl");
Create.ForeignKey("FK_umbracoRedirectUrl")
// SQL CE does not want to alter-add non-nullable columns ;-(
// but it's OK to create as nullable then alter, go figure
//localContext.Alter.Table("umbracoRedirectUrl")
// .AddColumn("contentKey").AsGuid().NotNullable();
localContext.Alter.Table("umbracoRedirectUrl")
.AddColumn("contentKey").AsGuid().Nullable();
localContext.Alter.Table("umbracoRedirectUrl")
.AlterColumn("contentKey").AsGuid().NotNullable();
localContext.Create.ForeignKey("FK_umbracoRedirectUrl")
.FromTable("umbracoRedirectUrl").ForeignColumn("contentKey")
.ToTable("umbracoNode").PrimaryColumn("uniqueID");
return localContext.GetSql();
}
public override void Down()

View File

@@ -14,19 +14,32 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZer
public override void Up()
{
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
// defer, because we are making decisions based upon what's in the database
Execute.Code(MigrationCode);
}
private string MigrationCode(Database database)
{
var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoRedirectUrl") && x.ColumnName.InvariantEquals("hurl")))
return;
return null;
Execute.Sql("DELETE FROM umbracoRedirectUrl"); // else cannot add non-nullable field
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
Delete.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl");
localContext.Execute.Sql("DELETE FROM umbracoRedirectUrl"); // else cannot add non-nullable field
Alter.Table("umbracoRedirectUrl")
.AddColumn("hurl").AsString(16).NotNullable();
localContext.Delete.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl");
Create.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl")
// SQL CE does not want to alter-add non-nullable columns ;-(
// but it's OK to create as nullable then alter, go figure
//localContext.Alter.Table("umbracoRedirectUrl")
// .AddColumn("urlHash").AsString(16).NotNullable();
localContext.Alter.Table("umbracoRedirectUrl")
.AddColumn("hurl").AsString(16).Nullable();
localContext.Alter.Table("umbracoRedirectUrl")
.AlterColumn("hurl").AsString(16).NotNullable();
localContext.Create.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl")
.OnColumn("hurl")
.Ascending()
.OnColumn("contentKey")
@@ -34,6 +47,8 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZer
.OnColumn("createDateUtc")
.Descending()
.WithOptions().NonClustered();
return localContext.GetSql();
}
public override void Down()

View File

@@ -0,0 +1,59 @@
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero
{
[Migration("7.5.0", 103, GlobalSettings.UmbracoMigrationName)]
public class AddRedirectUrlTable4 : MigrationBase
{
public AddRedirectUrlTable4(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{ }
public override void Up()
{
// defer, because we are making decisions based upon what's in the database
Execute.Code(MigrationCode);
}
private string MigrationCode(Database database)
{
var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoRedirectUrl") && x.ColumnName.InvariantEquals("urlHash")))
return null;
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
localContext.Execute.Sql("DELETE FROM umbracoRedirectUrl"); // else cannot add non-nullable field
localContext.Delete.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl");
localContext.Delete.Column("hurl").FromTable("umbracoRedirectUrl");
// SQL CE does not want to alter-add non-nullable columns ;-(
// but it's OK to create as nullable then alter, go figure
//localContext.Alter.Table("umbracoRedirectUrl")
// .AddColumn("urlHash").AsString(16).NotNullable();
localContext.Alter.Table("umbracoRedirectUrl")
.AddColumn("urlHash").AsString(16).Nullable();
localContext.Alter.Table("umbracoRedirectUrl")
.AlterColumn("urlHash").AsString(16).NotNullable();
localContext.Create.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl")
.OnColumn("urlHash")
.Ascending()
.OnColumn("contentKey")
.Ascending()
.OnColumn("createDateUtc")
.Descending()
.WithOptions().NonClustered();
return localContext.GetSql();
}
public override void Down()
{ }
}
}

View File

@@ -105,7 +105,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
ContentKey = redirectUrl.ContentKey,
CreateDateUtc = redirectUrl.CreateDateUtc,
Url = redirectUrl.Url,
Hurl = HashUrl(redirectUrl.Url)
UrlHash = HashUrl(redirectUrl.Url)
};
}
@@ -132,8 +132,8 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
public IRedirectUrl Get(string url, Guid contentKey)
{
var hurl = HashUrl(url);
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Url == url && x.Hurl == hurl && x.ContentKey == contentKey);
var urlHash = HashUrl(url);
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash && x.ContentKey == contentKey);
var dto = Database.Fetch<RedirectUrlDto>(sql).FirstOrDefault();
return dto == null ? null : Map(dto);
}
@@ -155,9 +155,9 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
public IRedirectUrl GetMostRecentUrl(string url)
{
var hurl = HashUrl(url);
var urlHash = HashUrl(url);
var sql = GetBaseQuery(false)
.Where<RedirectUrlDto>(x => x.Url == url && x.Hurl == hurl)
.Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash)
.OrderByDescending<RedirectUrlDto>(x => x.CreateDateUtc, SqlSyntax);
var dtos = Database.Fetch<RedirectUrlDto>(sql);
var dto = dtos.FirstOrDefault();
@@ -196,10 +196,10 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
private static string HashUrl(string url)
{
var h = new MD5CryptoServiceProvider();
var i = Encoding.UTF8.GetBytes(url);
var o = h.ComputeHash(i);
return Encoding.UTF8.GetString(o);
var crypto = new MD5CryptoServiceProvider();
var inputBytes = Encoding.UTF8.GetBytes(url);
var hashedBytes = crypto.ComputeHash(inputBytes);
return Encoding.UTF8.GetString(hashedBytes);
}
}
}

View File

@@ -425,7 +425,9 @@
<Compile Include="Persistence\Mappers\AccessMapper.cs" />
<Compile Include="Persistence\Mappers\DomainMapper.cs" />
<Compile Include="Persistence\Mappers\MigrationEntryMapper.cs" />
<Compile Include="Persistence\Migrations\LocalMigrationContext.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionFourOneZero\AddPreviewXmlTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\AddRedirectUrlTable4.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\AddRedirectUrlTable3.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\AddRedirectUrlTable2.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\EnsureServersLockObject.cs" />

View File

@@ -1,10 +1,20 @@
using System;
using System.Linq;
using Moq;
using NUnit.Framework;
using Semver;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven;
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero;
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using GlobalSettings = Umbraco.Core.Configuration.GlobalSettings;
namespace Umbraco.Tests.Migrations
{
@@ -90,5 +100,48 @@ namespace Umbraco.Tests.Migrations
Assert.AreEqual("[{\"title\":\"\",\"caption\":\"\",\"link\":\"\",\"newWindow\":false,\"type\":\"external\",\"internal\":null,\"edit\":false,\"isInternal\":false}]",
data.Text);
}
[Test]
public void Issue8361Test()
{
var logger = new DebugDiagnosticsLogger();
//Setup the MigrationRunner
var migrationRunner = new MigrationRunner(
Mock.Of<IMigrationEntryService>(),
logger,
new SemVersion(7, 4, 0),
new SemVersion(7, 5, 0),
GlobalSettings.UmbracoMigrationName,
//pass in explicit migrations
new DeleteRedirectUrlTable(SqlSyntax, logger),
new AddRedirectUrlTable(SqlSyntax, logger),
new AddRedirectUrlTable2(SqlSyntax, logger),
new AddRedirectUrlTable3(SqlSyntax, logger),
new AddRedirectUrlTable4(SqlSyntax, logger)
);
var db = new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;", "System.Data.SqlServerCe.4.0", Logger);
var upgraded = migrationRunner.Execute(db, DatabaseProviders.SqlServerCE, true);
Assert.IsTrue(upgraded);
}
[Migration("7.5.0", 99, GlobalSettings.UmbracoMigrationName)]
public class DeleteRedirectUrlTable : MigrationBase
{
public DeleteRedirectUrlTable(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{ }
public override void Up()
{
Delete.Table("umbracoRedirectUrl");
}
public override void Down()
{ }
}
}
}