From 7c720460f51a22fb092a8b8dec2d43a78ced4165 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 9 Jan 2014 10:33:35 +1100 Subject: [PATCH] Fixes: U4-3876 MySQL cmsContentXml Migration Error on 7.0.1 Upgrade --- src/Umbraco.Core/Services/ContentService.cs | 117 ++++++++++-------- src/Umbraco.Core/Services/MediaService.cs | 31 ++--- src/Umbraco.Core/Services/MemberService.cs | 39 ++++-- .../SyntaxProvider/SqlSyntaxProviderTests.cs | 1 + 4 files changed, 108 insertions(+), 80 deletions(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index e937560d79..29bb8c1711 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Caching; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Publishing; @@ -49,11 +50,11 @@ namespace Umbraco.Core.Services public ContentService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IPublishingStrategy publishingStrategy) { - if (provider == null) throw new ArgumentNullException("provider"); - if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory"); - if (publishingStrategy == null) throw new ArgumentNullException("publishingStrategy"); - _uowProvider = provider; - _publishingStrategy = publishingStrategy; + if (provider == null) throw new ArgumentNullException("provider"); + if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory"); + if (publishingStrategy == null) throw new ArgumentNullException("publishingStrategy"); + _uowProvider = provider; + _publishingStrategy = publishingStrategy; _repositoryFactory = repositoryFactory; } @@ -345,9 +346,9 @@ namespace Umbraco.Core.Services /// /// to retrieve ancestors for /// An Enumerable list of objects - public IEnumerable GetAncestors(IContent content) - { - var ids = content.Path.Split(',').Where(x => x != "-1" && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray(); + public IEnumerable GetAncestors(IContent content) + { + var ids = content.Path.Split(',').Where(x => x != "-1" && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray(); if (ids.Any() == false) return new List(); @@ -355,9 +356,9 @@ namespace Umbraco.Core.Services { return repository.GetAll(ids); } - } + } - /// + /// /// Gets a collection of objects by Parent Id /// /// Id of the Parent to retrieve Children from @@ -441,7 +442,7 @@ namespace Umbraco.Core.Services return GetById(content.ParentId); } - /// + /// /// Gets the published version of an item /// /// Id of the to retrieve version from @@ -593,7 +594,7 @@ namespace Umbraco.Core.Services { LogHelper.Error("An error occurred executing RePublishAll", ex); return false; - } + } } /// @@ -612,7 +613,7 @@ namespace Umbraco.Core.Services catch (Exception ex) { LogHelper.Error("An error occurred executing RePublishAll", ex); - } + } } /// @@ -1354,7 +1355,7 @@ namespace Umbraco.Core.Services if (raiseEvents) Saved.RaiseEvent(new SaveEventArgs(items, false), this); - if(shouldBePublished.Any()) + if (shouldBePublished.Any()) _publishingStrategy.PublishingFinalized(shouldBePublished, false); Audit.Add(AuditTypes.Sort, "Sorting content performed by user", userId, 0); @@ -1363,7 +1364,7 @@ namespace Umbraco.Core.Services } #region Internal Methods - + /// /// Internal method that Publishes a single object for legacy purposes. /// @@ -1375,14 +1376,14 @@ namespace Umbraco.Core.Services return SaveAndPublishDo(content, userId); } - /// - /// Internal method that Publishes a object and all its children for legacy purposes. - /// - /// The to publish along with its children - /// Optional Id of the User issueing the publishing - /// If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published - /// True if publishing succeeded, otherwise False - internal IEnumerable> PublishWithChildrenInternal( + /// + /// Internal method that Publishes a object and all its children for legacy purposes. + /// + /// The to publish along with its children + /// Optional Id of the User issueing the publishing + /// If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published + /// True if publishing succeeded, otherwise False + internal IEnumerable> PublishWithChildrenInternal( IContent content, int userId = 0, bool includeUnpublished = false) { return PublishWithChildrenDo(content, userId, includeUnpublished); @@ -1459,20 +1460,32 @@ namespace Umbraco.Core.Services { if (contentTypeIds.Any() == false) { - //Remove all Document records from the cmsContentXml table (DO NOT REMOVE Media/Members!) - uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN - (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml - INNER JOIN cmsDocument ON cmsContentXml.nodeId = cmsDocument.nodeId)"); + //Remove all Document records from the cmsContentXml table (DO NOT REMOVE Media/Members!) (based on inner join of cmsDocument) + var subQuery = new Sql() + .Select("DISTINCT cmsContentXml.nodeId") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId); + + var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery); + uow.Database.Execute(deleteSql); } else { foreach (var id in contentTypeIds) { //first we'll clear out the data from the cmsContentXml table for this type - uow.Database.Execute(@"delete from cmsContentXml where nodeId in -(select cmsDocument.nodeId from cmsDocument - inner join cmsContent on cmsDocument.nodeId = cmsContent.nodeId - where published = 1 and contentType = @contentTypeId)", new { contentTypeId = id }); + var id1 = id; + var subQuery = new Sql() + .Select("cmsDocument.nodeId") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .Where(dto => dto.Published) + .Where(dto => dto.ContentTypeId == id1); + + var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery); + uow.Database.Execute(deleteSql); } } @@ -1481,27 +1494,27 @@ namespace Umbraco.Core.Services } Audit.Add(AuditTypes.Publish, "RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1); - } + } } - /// - /// Publishes a object and all its children - /// - /// The to publish along with its children - /// Optional Id of the User issueing the publishing - /// If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published - /// - /// A list of publish statues. If the parent document is not valid or cannot be published because it's parent(s) is not published - /// then the list will only contain one status item, otherwise it will contain status items for it and all of it's descendants that - /// are to be published. - /// - private IEnumerable> PublishWithChildrenDo( + /// + /// Publishes a object and all its children + /// + /// The to publish along with its children + /// Optional Id of the User issueing the publishing + /// If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published + /// + /// A list of publish statues. If the parent document is not valid or cannot be published because it's parent(s) is not published + /// then the list will only contain one status item, otherwise it will contain status items for it and all of it's descendants that + /// are to be published. + /// + private IEnumerable> PublishWithChildrenDo( IContent content, int userId = 0, bool includeUnpublished = false) { - if (content == null) throw new ArgumentNullException("content"); + if (content == null) throw new ArgumentNullException("content"); - using (new WriteLock(Locker)) - { + using (new WriteLock(Locker)) + { var result = new List>(); //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published @@ -1525,7 +1538,7 @@ namespace Umbraco.Core.Services Attempt.Fail( new PublishStatus(content, PublishStatusType.FailedContentInvalid) { - InvalidProperties = ((ContentBase) content).LastInvalidProperties + InvalidProperties = ((ContentBase)content).LastInvalidProperties })); return result; } @@ -1576,7 +1589,7 @@ namespace Umbraco.Core.Services return publishedOutcome; - } + } } /// @@ -1622,7 +1635,7 @@ namespace Umbraco.Core.Services /// Optional Id of the User issueing the publishing /// Optional boolean indicating whether or not to raise save events. /// True if publishing succeeded, otherwise False - private Attempt SaveAndPublishDo(IContent content, int userId = 0, bool raiseEvents = true) + private Attempt SaveAndPublishDo(IContent content, int userId = 0, bool raiseEvents = true) { if (raiseEvents) { @@ -1646,7 +1659,7 @@ namespace Umbraco.Core.Services //Content contains invalid property values and can therefore not be published - fire event? publishStatus.StatusType = CheckAndLogIsValid(content); //set the invalid properties (if there are any) - publishStatus.InvalidProperties = ((ContentBase)content).LastInvalidProperties; + publishStatus.InvalidProperties = ((ContentBase)content).LastInvalidProperties; } //if we're still successful, then publish using the strategy if (publishStatus.StatusType == PublishStatusType.Success) @@ -1706,7 +1719,7 @@ namespace Umbraco.Core.Services Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId, content.Id); return Attempt.If(publishStatus.StatusType == PublishStatusType.Success, publishStatus); - } + } } /// diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index 5ce8beb988..b4d8868e5e 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -904,34 +904,35 @@ namespace Umbraco.Core.Services { if (contentTypeIds.Any() == false) { + var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media); var subQuery = new Sql() .Select("DISTINCT cmsContentXml.nodeId") .From() .InnerJoin() .On(left => left.NodeId, right => right.NodeId) - .Where(dto => dto.NodeObjectType == Guid.Parse(Constants.ObjectTypes.Media)); + .Where(dto => dto.NodeObjectType == mediaObjectType); var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery); uow.Database.Execute(deleteSql); - - // //Remove all media records from the cmsContentXml table (DO NOT REMOVE Content/Members!) - // uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN - // (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml - // INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id - // WHERE nodeObjectType = @nodeObjectType)", - // new { nodeObjectType = Constants.ObjectTypes.Media }); } else { foreach (var id in contentTypeIds) { - //first we'll clear out the data from the cmsContentXml table for this type - uow.Database.Execute(@"delete from cmsContentXml where nodeId in - (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml - INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id - INNER JOIN cmsContent ON cmsContent.nodeId = umbracoNode.id - WHERE nodeObjectType = @nodeObjectType AND cmsContent.contentType = @contentTypeId)", - new { contentTypeId = id, nodeObjectType = Constants.ObjectTypes.Media }); + var id1 = id; + var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media); + var subQuery = new Sql() + .Select("DISTINCT cmsContentXml.nodeId") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .Where(dto => dto.NodeObjectType == mediaObjectType) + .Where(dto => dto.ContentTypeId == id1); + + var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery); + uow.Database.Execute(deleteSql); } } diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index d82a429662..db3bdb9c48 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; using System.Linq; @@ -757,24 +758,36 @@ namespace Umbraco.Core.Services { if (memberTypeIds.Any() == false) { - //Remove all media records from the cmsContentXml table (DO NOT REMOVE Content/Members!) - uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN - (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml - INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id - WHERE nodeObjectType = @nodeObjectType)", - new { nodeObjectType = Constants.ObjectTypes.Member }); + //Remove all member records from the cmsContentXml table (DO NOT REMOVE Content/Media!) + var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member); + var subQuery = new Sql() + .Select("DISTINCT cmsContentXml.nodeId") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .Where(dto => dto.NodeObjectType == memberObjectType); + + var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery); + uow.Database.Execute(deleteSql); } else { foreach (var id in memberTypeIds) { - //first we'll clear out the data from the cmsContentXml table for this type - uow.Database.Execute(@"delete from cmsContentXml where nodeId in - (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml - INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id - INNER JOIN cmsContent ON cmsContent.nodeId = umbracoNode.id - WHERE nodeObjectType = @nodeObjectType AND cmsContent.contentType = @contentTypeId)", - new { contentTypeId = id, nodeObjectType = Constants.ObjectTypes.Member }); + var id1 = id; + var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member); + var subQuery = new Sql() + .Select("DISTINCT cmsContentXml.nodeId") + .From() + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .InnerJoin() + .On(left => left.NodeId, right => right.NodeId) + .Where(dto => dto.NodeObjectType == memberObjectType) + .Where(dto => dto.ContentTypeId == id1); + + var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery); + uow.Database.Execute(deleteSql); } } diff --git a/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlSyntaxProviderTests.cs b/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlSyntaxProviderTests.cs index b8d8347482..7802ea6d58 100644 --- a/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlSyntaxProviderTests.cs +++ b/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlSyntaxProviderTests.cs @@ -31,6 +31,7 @@ namespace Umbraco.Tests.Persistence.SyntaxProvider .InnerJoin() .On(left => left.NodeId, right => right.NodeId) .Where(dto => dto.NodeObjectType == mediaObjectType); + var sql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery); Assert.AreEqual(@"DELETE FROM [cmsContentXml] WHERE [nodeId] IN (SELECT [nodeId] FROM (SELECT DISTINCT cmsContentXml.nodeId