Merge pull request #1380 from umbraco/temp-U4-8522

U4-8522 cmsPropertyData needs unique constraint indexes and index refactoring
This commit is contained in:
Sebastiaan Janssen
2016-07-15 09:22:31 +02:00
committed by GitHub
7 changed files with 99 additions and 7 deletions

View File

@@ -16,7 +16,7 @@ namespace Umbraco.Core.Models.Rdbms
[Column("contentNodeId")]
[ForeignKey(typeof(NodeDto))]
[Index(IndexTypes.NonClustered, Name = "IX_cmsPropertyData_1")]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsPropertyData_1", ForColumns = "contentNodeId,versionId,propertytypeid")]
public int NodeId { get; set; }
[Column("versionId")]

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using System;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Index
@@ -17,12 +18,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Index
return this;
}
[Obsolete("I don't think this would ever be used when dropping an index, see DeleteIndexExpression.ToString")]
public void OnColumn(string columnName)
{
var column = new IndexColumnDefinition { Name = columnName };
Expression.Index.Columns.Add(column);
}
[Obsolete("I don't think this would ever be used when dropping an index, see DeleteIndexExpression.ToString")]
public void OnColumns(params string[] columnNames)
{
foreach (string columnName in columnNames)

View File

@@ -1,8 +1,13 @@
namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Index
using System;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Index
{
public interface IDeleteIndexOnColumnSyntax : IFluentSyntax
{
[Obsolete("I don't think this would ever be used when dropping an index, see DeleteIndexExpression.ToString")]
void OnColumn(string columnName);
[Obsolete("I don't think this would ever be used when dropping an index, see DeleteIndexExpression.ToString")]
void OnColumns(params string[] columnNames);
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero
{
/// <summary>
/// See: http://issues.umbraco.org/issue/U4-8522
/// </summary>
[Migration("7.5.0", 2, GlobalSettings.UmbracoMigrationName)]
public class UpdateUniqueIndexOnCmsPropertyData : MigrationBase
{
public UpdateUniqueIndexOnCmsPropertyData(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{
}
public override void Up()
{
//Clear all stylesheet data if the tables exist
//tuple = tablename, indexname, columnname, unique
var indexes = SqlSyntax.GetDefinedIndexes(Context.Database).ToArray();
var found = indexes.FirstOrDefault(
x => x.Item1.InvariantEquals("cmsPropertyData")
&& x.Item2.InvariantEquals("IX_cmsPropertyData_1")
//we're searching for the old index which is not unique
&& x.Item4 == false);
if (found != null)
{
//Check for MySQL
if (Context.CurrentDatabaseProvider == DatabaseProviders.MySql)
{
//Use the special double nested sub query for MySQL since that is the only
//way delete sub queries works
SqlSyntax.GetDeleteSubquery(
"cmsPropertyData",
"id",
new Sql("SELECT MIN(id) FROM cmsPropertyData GROUP BY contentNodeId, versionId, propertytypeid HAVING MIN(id) IS NOT NULL"),
WhereInType.NotIn);
}
else
{
//NOTE: Even though the above will work for MSSQL, we are not going to execute the
// nested delete sub query logic since it will be slower and there could be a ton of property
// data here so needs to be as fast as possible.
Execute.Sql("DELETE FROM cmsPropertyData WHERE id NOT IN (SELECT MIN(id) FROM cmsPropertyData GROUP BY contentNodeId, versionId, propertytypeid HAVING MIN(id) IS NOT NULL)");
}
//we need to re create this index
Delete.Index("IX_cmsPropertyData_1").OnTable("cmsPropertyData");
Create.Index("IX_cmsPropertyData_1").OnTable("cmsPropertyData")
.OnColumn("contentNodeId").Ascending()
.OnColumn("versionId").Ascending()
.OnColumn("propertytypeid").Ascending()
.WithOptions().NonClustered()
.WithOptions().Unique();
}
}
public override void Down()
{
}
}
}

View File

@@ -22,12 +22,23 @@
/// <remarks>
/// See: http://issues.umbraco.org/issue/U4-3876
/// </remarks>
public static Sql GetDeleteSubquery(this ISqlSyntaxProvider sqlProvider, string tableName, string columnName, Sql subQuery)
public static Sql GetDeleteSubquery(this ISqlSyntaxProvider sqlProvider, string tableName, string columnName, Sql subQuery, WhereInType whereInType = WhereInType.In)
{
return new Sql(string.Format(@"DELETE FROM {0} WHERE {1} IN (SELECT {1} FROM ({2}) x)",
return
new Sql(string.Format(
whereInType == WhereInType.In
? @"DELETE FROM {0} WHERE {1} IN (SELECT {1} FROM ({2}) x)"
: @"DELETE FROM {0} WHERE {1} NOT IN (SELECT {1} FROM ({2}) x)",
sqlProvider.GetQuotedTableName(tableName),
sqlProvider.GetQuotedColumnName(columnName),
subQuery.SQL), subQuery.Arguments);
}
}
internal enum WhereInType
{
In,
NotIn
}
}

View File

@@ -433,6 +433,7 @@
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\EnsureServersLockObject.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\AddRedirectUrlTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\RemoveStylesheetDataAndTablesAgain.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\UpdateUniqueIndexOnCmsPropertyData.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\FixListViewMediaSortOrder.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\AddDataDecimalColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\AddUmbracoDeployTables.cs" />

View File

@@ -81,14 +81,16 @@ namespace Umbraco.Tests.Migrations
{
NodeId = n.NodeId,
PropertyTypeId = pt.Id,
Text = "text"
Text = "text",
VersionId = Guid.NewGuid()
};
DatabaseContext.Database.Insert(data);
data = new PropertyDataDto
{
NodeId = n.NodeId,
PropertyTypeId = pt.Id,
Text = "<root><node title=\"\" type=\"\" newwindow=\"\" link=\"\" /></root>"
Text = "<root><node title=\"\" type=\"\" newwindow=\"\" link=\"\" /></root>",
VersionId = Guid.NewGuid()
};
DatabaseContext.Database.Insert(data);