From e843b2c7ea98ab84e18f199ecd035bd0863400e5 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 22 Nov 2017 12:45:09 +0100 Subject: [PATCH] Troubleshoot variants migration --- src/Umbraco.Core/Models/Language.cs | 20 +++-- src/Umbraco.Core/Models/Rdbms/ContentDto.cs | 7 -- .../Persistence/Factories/ContentFactory.cs | 6 +- .../Persistence/Factories/MediaFactory.cs | 6 +- .../Persistence/Factories/MemberFactory.cs | 6 +- .../TargetVersionEight/VariantsMigration.cs | 78 +++++++++++-------- .../Repositories/ContentRepository.cs | 2 +- 7 files changed, 60 insertions(+), 65 deletions(-) diff --git a/src/Umbraco.Core/Models/Language.cs b/src/Umbraco.Core/Models/Language.cs index 52257ef2f3..98acd7430b 100644 --- a/src/Umbraco.Core/Models/Language.cs +++ b/src/Umbraco.Core/Models/Language.cs @@ -7,12 +7,14 @@ using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Models { /// - /// Represents a Language + /// Represents a Language. /// [Serializable] [DataContract(IsReference = true)] public class Language : Entity, ILanguage { + private static readonly Lazy Ps = new Lazy(); + private string _isoCode; private string _cultureName; @@ -21,8 +23,7 @@ namespace Umbraco.Core.Models IsoCode = isoCode; } - private static readonly Lazy Ps = new Lazy(); - + // ReSharper disable once ClassNeverInstantiated.Local private class PropertySelectors { public readonly PropertyInfo IsoCodeSelector = ExpressionHelper.GetPropertyInfo(x => x.IsoCode); @@ -35,8 +36,8 @@ namespace Umbraco.Core.Models [DataMember] public string IsoCode { - get { return _isoCode; } - set { SetPropertyValueAndDetectChanges(value, ref _isoCode, Ps.Value.IsoCodeSelector); } + get => _isoCode; + set => SetPropertyValueAndDetectChanges(value, ref _isoCode, Ps.Value.IsoCodeSelector); } /// @@ -45,17 +46,14 @@ namespace Umbraco.Core.Models [DataMember] public string CultureName { - get { return _cultureName; } - set { SetPropertyValueAndDetectChanges(value, ref _cultureName, Ps.Value.CultureNameSelector); } + get => _cultureName; + set => SetPropertyValueAndDetectChanges(value, ref _cultureName, Ps.Value.CultureNameSelector); } /// /// Returns a object for the current Language /// [IgnoreDataMember] - public CultureInfo CultureInfo - { - get { return CultureInfo.GetCultureInfo(IsoCode); } - } + public CultureInfo CultureInfo => CultureInfo.GetCultureInfo(IsoCode); } } diff --git a/src/Umbraco.Core/Models/Rdbms/ContentDto.cs b/src/Umbraco.Core/Models/Rdbms/ContentDto.cs index 8e3e05064c..19f6f8b4f1 100644 --- a/src/Umbraco.Core/Models/Rdbms/ContentDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/ContentDto.cs @@ -21,13 +21,6 @@ namespace Umbraco.Core.Models.Rdbms [ForeignKey(typeof(ContentTypeDto), Column = "NodeId")] public int ContentTypeId { get; set; } - [Column("writerUserId")] - public int WriterUserId { get; set; } - - [Column("updateDate")] - [Constraint(Default = SystemMethods.CurrentDateTime)] - public DateTime UpdateDate { get; set; } - [ResultColumn] [Reference(ReferenceType.OneToOne, ColumnName = "NodeId")] public NodeDto NodeDto { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs index 9d54f7b80d..22f5191009 100644 --- a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs @@ -38,9 +38,9 @@ namespace Umbraco.Core.Persistence.Factories content.Trashed = nodeDto.Trashed; content.CreatorId = nodeDto.UserId ?? 0; - content.WriterId = contentDto.WriterUserId; + content.WriterId = contentVersionDto.UserId; content.CreateDate = nodeDto.CreateDate; - content.UpdateDate = contentDto.UpdateDate; + content.UpdateDate = contentVersionDto.VersionDate; content.Published = dto.Published; content.Edited = dto.Edited; @@ -94,8 +94,6 @@ namespace Umbraco.Core.Persistence.Factories { NodeId = entity.Id, ContentTypeId = entity.ContentTypeId, - WriterUserId = entity.WriterId, - UpdateDate = entity.UpdateDate, NodeDto = BuildNodeDto(entity, objectType) }; diff --git a/src/Umbraco.Core/Persistence/Factories/MediaFactory.cs b/src/Umbraco.Core/Persistence/Factories/MediaFactory.cs index 61b74213cc..ef1a6abaa1 100644 --- a/src/Umbraco.Core/Persistence/Factories/MediaFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MediaFactory.cs @@ -34,9 +34,9 @@ namespace Umbraco.Core.Persistence.Factories content.Trashed = nodeDto.Trashed; content.CreatorId = nodeDto.UserId ?? 0; - content.WriterId = dto.WriterUserId; + content.WriterId = contentVersionDto.UserId; content.CreateDate = nodeDto.CreateDate; - content.UpdateDate = dto.UpdateDate; + content.UpdateDate = contentVersionDto.VersionDate; // reset dirty initial properties (U4-1946) content.ResetDirtyProperties(false); @@ -64,8 +64,6 @@ namespace Umbraco.Core.Persistence.Factories { NodeId = entity.Id, ContentTypeId = entity.ContentTypeId, - WriterUserId = entity.WriterId, - UpdateDate = entity.UpdateDate, NodeDto = BuildNodeDto(entity, objectType) }; diff --git a/src/Umbraco.Core/Persistence/Factories/MemberFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberFactory.cs index 6b05ea65f7..fd9b2fb6c0 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberFactory.cs @@ -34,9 +34,9 @@ namespace Umbraco.Core.Persistence.Factories content.Trashed = nodeDto.Trashed; content.CreatorId = nodeDto.UserId ?? 0; - content.WriterId = dto.ContentDto.WriterUserId; + content.WriterId = contentVersionDto.UserId; content.CreateDate = nodeDto.CreateDate; - content.UpdateDate = dto.ContentDto.UpdateDate; + content.UpdateDate = contentVersionDto.VersionDate; content.ProviderUserKey = content.Key; // fixme explain @@ -76,8 +76,6 @@ namespace Umbraco.Core.Persistence.Factories { NodeId = entity.Id, ContentTypeId = entity.ContentTypeId, - WriterUserId = entity.WriterId, - UpdateDate = entity.UpdateDate, NodeDto = BuildNodeDto(entity, objectType) }; diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionEight/VariantsMigration.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionEight/VariantsMigration.cs index 31c8d7ba55..561bd13250 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionEight/VariantsMigration.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionEight/VariantsMigration.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.DatabaseModelDefinitions; @@ -29,6 +30,30 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionEight MigrateContent(); MigrateVersions(); + Execute.Code(context => + { + if (context.Database.Fetch(@"SELECT uContentVersion.nodeId, COUNT(uContentVersion.id) +FROM uContentVersion +JOIN uDocumentVersion ON uContentVersion.id=uDocumentVersion.id +WHERE uDocumentVersion.published=1 +GROUP BY uContentVersion.nodeId +HAVING COUNT(uContentVersion.id) > 1").Any()) + { + Debugger.Break(); + throw new Exception("Migration failed: duplicate 'published' document versions."); + } + if (context.Database.Fetch(@"SELECT v1.nodeId, v1.id, COUNT(v2.id) +FROM uContentVersion v1 +LEFT JOIN uContentVersion v2 ON v1.nodeId=v2.nodeId AND v2.[current]=1 +GROUP BY v1.nodeId, v1.id +HAVING COUNT(v2.id) <> 1").Any()) + { + Debugger.Break(); + throw new Exception("Migration failed: missing or duplicate 'current' content versions."); + } + return string.Empty; + }); + // re-create *all* keys and indexes //Create.KeysAndIndexes(); foreach (var x in DatabaseSchemaCreation.OrderedTables) @@ -93,32 +118,6 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionEight if (ColumnExists(PreTables.Content, "contentType")) ReplaceColumn(PreTables.Content, "contentType", "contentTypeId"); - // add columns - // fixme - why? why cannot we do it with the current version? we don't need those two columns! - if (!ColumnExists(PreTables.Content, "writerUserId")) - { - AddColumn(PreTables.Content, "writerUserId", out var sqls); - Execute.Sql($"UPDATE {PreTables.Content} SET writerUserId=0"); - foreach (var sql in sqls) Execute.Sql(sql); - } - if (!ColumnExists(PreTables.Content, "updateDate")) - { - AddColumn(PreTables.Content, "updateDate", out var sqls); - var getDate = Context.SqlContext.DatabaseType.IsMySql() ? "CURRENT_TIMESTAMP" : "GETDATE()"; // sqlSyntax should do it! - Execute.Sql($"UPDATE {PreTables.Content} SET updateDate=" + getDate); - foreach (var sql in sqls) Execute.Sql(sql); - } - - // copy data for added columns - Execute.Code(context => - { - // SQLCE does not support UPDATE...FROM - var temp = context.Database.Fetch($"SELECT nodeId, documentUser, updateDate FROM {PreTables.Document} WHERE newest=1"); - foreach (var t in temp) - context.Database.Execute($@"UPDATE {PreTables.Content} SET writerUserId=@userId, updateDate=@updateDate", new { userId = t.documentUser, updateDate = t.updateDate }); - return string.Empty; - }); - // drop columns if (ColumnExists(PreTables.Content, "pk")) Delete.Column("pk").FromTable(PreTables.Content); @@ -196,32 +195,43 @@ WHERE cver.versionId NOT IN (SELECT versionId FROM {SqlSyntax.GetQuotedTableName Execute.Sql($@"INSERT INTO {SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.DocumentVersion)} (id, templateId, published) SELECT cver.id, doc.templateId, doc.published FROM {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} cver -JOIN {SqlSyntax.GetQuotedTableName(PreTables.Document)} doc ON doc.versionId=cver.versionId"); +JOIN {SqlSyntax.GetQuotedTableName(PreTables.Document)} doc ON doc.nodeId=cver.nodeId AND doc.versionId=cver.versionId"); // need to add extra rows for where published=newest // 'cos INSERT above has inserted the 'published' document version // and v8 always has a 'edited' document version too Execute.Code(context => { - var temp = context.Database.Fetch($@"SELECT doc.nodeId, doc.versionId, doc.updateDate, doc.documentUser, doc.text, doc.templateId + var temp = context.Database.Fetch($@"SELECT doc.nodeId, doc.updateDate, doc.documentUser, doc.text, doc.templateId, cver.id versionId FROM {SqlSyntax.GetQuotedTableName(PreTables.Document)} doc +JOIN {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} cver ON doc.nodeId=cver.nodeId AND doc.versionId=cver.versionId WHERE doc.newest=1 AND doc.published=1"); + var getIdentity = context.SqlContext.DatabaseType.IsMySql() + ? "LAST_INSERT_ID()" + : "@@@@IDENTITY"; foreach (var t in temp) { context.Database.Execute($@"INSERT INTO {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} (nodeId, versionId, versionDate, userId, {SqlSyntax.GetQuotedColumnName("current")}, text) -VALUES (@nodeId, @versionId, @versionDate, @userId, 1, @text)", new { nodeId=t.nodeId, versionId= Guid.NewGuid(), versionDate=t.updateDate, userId=t.documentUser, text=t.text }); - var id = context.Database.ExecuteScalar($@"SELECT @@@@IDENTITY"); // fixme mysql +VALUES (@nodeId, @versionId, @versionDate, @userId, 1, @text)", new { nodeId=t.nodeId, versionId=Guid.NewGuid(), versionDate=t.updateDate, userId=t.documentUser, text=t.text }); + var id = context.Database.ExecuteScalar("SELECT " + getIdentity); + context.Database.Execute($"UPDATE {SqlSyntax.GetQuotedTableName(PreTables.ContentVersion)} SET {SqlSyntax.GetQuotedColumnName("current")}=0 WHERE nodeId=@0 AND id<>@1", (int) t.nodeId, id); context.Database.Execute($@"INSERT INTO {SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.DocumentVersion)} (id, templateId, published) -VALUES (@id, @templateId, 1)", new { id=id, templateId=t.templateId }); +VALUES (@id, @templateId, 0)", new { id=id, templateId=t.templateId }); + + var versionId = (int) t.versionId; + var pdatas = context.Database.Fetch(Sql().Select().From().Where(x => x.VersionId == versionId)); + foreach (var pdata in pdatas) + { + pdata.VersionId = id; + context.Database.Insert(pdata); + } } return string.Empty; }); - // fixme these extra rows need propertydata too! - // reduce document to 1 row per content Execute.Sql($@"DELETE FROM {PreTables.Document} -WHERE versionId NOT IN (SELECT (versionId) FROM {PreTables.ContentVersion} WHERE {SqlSyntax.GetQuotedColumnName("current")} = 1)"); +WHERE versionId NOT IN (SELECT (versionId) FROM {PreTables.ContentVersion} WHERE {SqlSyntax.GetQuotedColumnName("current")} = 1) AND (published<>1 OR newest<>1)"); // drop some document columns Delete.Column("text").FromTable(PreTables.Document); diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 8df698ce0f..88ac07c448 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -740,7 +740,7 @@ namespace Umbraco.Core.Persistence.Repositories { case "UPDATER": // fixme orders by id not letter = bad - return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.Document, "writerUserId"); + return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.ContentVersion, "userId"); case "PUBLISHED": // fixme kill return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.Document, "published");