U4-8998 umbracoRelation table needs unique index on columns: parentId, childId, relType
This commit is contained in:
@@ -16,6 +16,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[Column("parentId")]
|
||||
[ForeignKey(typeof(NodeDto), Name = "FK_umbracoRelation_umbracoNode")]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelation_parentChildType", ForColumns = "parentId,childId,relType")]
|
||||
public int ParentId { get; set; }
|
||||
|
||||
[Column("childId")]
|
||||
|
||||
@@ -14,14 +14,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodePath")) == false)
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
{
|
||||
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
|
||||
public class AddIndexesToUmbracoRelation : MigrationBase
|
||||
{
|
||||
public AddIndexesToUmbracoRelation(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
//Ensure this executes in a defered block which will be done inside of the migration transaction
|
||||
this.Execute.Code(database =>
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(database);
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelation_parentChildType")) == false)
|
||||
{
|
||||
//We need to check if this index has corrupted data and then clear that data
|
||||
var duplicates = database.Fetch<dynamic>("SELECT parentId,childId,relType FROM umbracoRelation GROUP BY parentId,childId,relType HAVING COUNT(*) > 1");
|
||||
if (duplicates.Count > 0)
|
||||
{
|
||||
//need to fix this there cannot be duplicates so we'll take the latest entries, it's really not going to matter though
|
||||
foreach (var duplicate in duplicates)
|
||||
{
|
||||
var ids = database.Fetch<int>("SELECT id FROM umbracoRelation WHERE parentId=@parentId AND childId=@childId AND relType=@relType ORDER BY datetime DESC",
|
||||
new { parentId = duplicate.parentId, childId = duplicate.childId, relType = duplicate.relType });
|
||||
|
||||
if (ids.Count == 1)
|
||||
{
|
||||
//this is just a safety check, this should absolutely never happen
|
||||
throw new InvalidOperationException("Duplicates were detected but could not be discovered");
|
||||
}
|
||||
|
||||
//delete the others
|
||||
ids = ids.Skip(0).ToList();
|
||||
|
||||
//iterate in groups of 2000 to avoid the max sql parameter limit
|
||||
foreach (var idGroup in ids.InGroupsOf(2000))
|
||||
{
|
||||
database.Execute("DELETE FROM umbracoRelation WHERE id IN (@ids)", new { ids = idGroup });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
Create.Index("IX_umbracoRelation_parentChildType").OnTable("umbracoRelation")
|
||||
.OnColumn("parentId").Ascending()
|
||||
.OnColumn("childId").Ascending()
|
||||
.OnColumn("relType").Ascending()
|
||||
.WithOptions()
|
||||
.Unique();
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
Delete.Index("IX_umbracoNodePath").OnTable("umbracoNode");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,23 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
internal static class SqlSyntaxProviderExtensions
|
||||
{
|
||||
public static IEnumerable<DbIndexDefinition> GetDefinedIndexesDefinitions(this ISqlSyntaxProvider sql, Database db)
|
||||
{
|
||||
return sql.GetDefinedIndexes(db)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the quotes tableName.columnName combo
|
||||
/// </summary>
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(commit: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateRelationRepository(uow);
|
||||
var query = new Query<IRelation>().Where(x => x.ChildId == id || x.ParentId == id);
|
||||
var query = new Query<IRelation>().Where(x => x.ParentId == id || x.ChildId == id);
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Core.Services
|
||||
if (relationType == null) return Enumerable.Empty<IRelation>();
|
||||
|
||||
var relationRepo = RepositoryFactory.CreateRelationRepository(uow);
|
||||
var query = new Query<IRelation>().Where(x => (x.ChildId == id || x.ParentId == id) && x.RelationTypeId == relationType.Id);
|
||||
var query = new Query<IRelation>().Where(x => (x.ParentId == id || x.ChildId == id) && x.RelationTypeId == relationType.Id);
|
||||
return relationRepo.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,6 +479,7 @@
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\AddUniqueIdPropertyTypeGroupColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\RemoveParentIdPropertyTypeGroupColumn.cs" />
|
||||
<Compile Include="Persistence\Mappers\TaskTypeMapper.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexesToUmbracoRelation.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToUmbracoNodePath.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddRelationTypeUniqueIdColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddMacroUniqueIdColumn.cs" />
|
||||
|
||||
@@ -121,6 +121,19 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
|
||||
Assert.AreEqual("CREATE UNIQUE NONCLUSTERED INDEX [IX_A] ON [TheTable] ([A])", createExpression.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateIndexBuilder_SqlServer_Unique_CreatesUniqueNonClusteredIndex_Multi_Columnn()
|
||||
{
|
||||
var sqlSyntax = new SqlServerSyntaxProvider();
|
||||
var createExpression = new CreateIndexExpression(DatabaseProviders.SqlServer, new[] { DatabaseProviders.SqlServer }, sqlSyntax)
|
||||
{
|
||||
Index = { Name = "IX_AB" }
|
||||
};
|
||||
var builder = new CreateIndexBuilder(createExpression);
|
||||
builder.OnTable("TheTable").OnColumn("A").Ascending().OnColumn("B").Ascending().WithOptions().Unique();
|
||||
Assert.AreEqual("CREATE UNIQUE NONCLUSTERED INDEX [IX_AB] ON [TheTable] ([A],[B])", createExpression.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateIndexBuilder_SqlServer_Clustered_CreatesClusteredIndex()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user