Fixes: U4-3876 MySQL cmsContentXml Migration Error on 7.0.1 Upgrade

This commit is contained in:
Shannon
2014-01-09 10:33:35 +11:00
parent 961755336a
commit 7c720460f5
4 changed files with 108 additions and 80 deletions

View File

@@ -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
/// </summary>
/// <param name="content"><see cref="IContent"/> to retrieve ancestors for</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetAncestors(IContent content)
{
var ids = content.Path.Split(',').Where(x => x != "-1" && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray();
public IEnumerable<IContent> 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<IContent>();
@@ -355,9 +356,9 @@ namespace Umbraco.Core.Services
{
return repository.GetAll(ids);
}
}
}
/// <summary>
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
@@ -441,7 +442,7 @@ namespace Umbraco.Core.Services
return GetById(content.ParentId);
}
/// <summary>
/// <summary>
/// Gets the published version of an <see cref="IContent"/> item
/// </summary>
/// <param name="id">Id of the <see cref="IContent"/> to retrieve version from</param>
@@ -593,7 +594,7 @@ namespace Umbraco.Core.Services
{
LogHelper.Error<ContentService>("An error occurred executing RePublishAll", ex);
return false;
}
}
}
/// <summary>
@@ -612,7 +613,7 @@ namespace Umbraco.Core.Services
catch (Exception ex)
{
LogHelper.Error<ContentService>("An error occurred executing RePublishAll", ex);
}
}
}
/// <summary>
@@ -1354,7 +1355,7 @@ namespace Umbraco.Core.Services
if (raiseEvents)
Saved.RaiseEvent(new SaveEventArgs<IContent>(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
/// <summary>
/// Internal method that Publishes a single <see cref="IContent"/> object for legacy purposes.
/// </summary>
@@ -1375,14 +1376,14 @@ namespace Umbraco.Core.Services
return SaveAndPublishDo(content, userId);
}
/// <summary>
/// Internal method that Publishes a <see cref="IContent"/> object and all its children for legacy purposes.
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="includeUnpublished">If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
internal IEnumerable<Attempt<PublishStatus>> PublishWithChildrenInternal(
/// <summary>
/// Internal method that Publishes a <see cref="IContent"/> object and all its children for legacy purposes.
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="includeUnpublished">If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
internal IEnumerable<Attempt<PublishStatus>> 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<ContentXmlDto>()
.InnerJoin<DocumentDto>()
.On<ContentXmlDto, DocumentDto>(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<DocumentDto>()
.InnerJoin<ContentDto>()
.On<DocumentDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.Where<DocumentDto>(dto => dto.Published)
.Where<ContentDto>(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);
}
}
}
/// <summary>
/// Publishes a <see cref="IContent"/> object and all its children
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="includeUnpublished">If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published</param>
/// <returns>
/// 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.
/// </returns>
private IEnumerable<Attempt<PublishStatus>> PublishWithChildrenDo(
/// <summary>
/// Publishes a <see cref="IContent"/> object and all its children
/// </summary>
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="includeUnpublished">If set to true, this will also publish descendants that are completely unpublished, normally this will only publish children that have previously been published</param>
/// <returns>
/// 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.
/// </returns>
private IEnumerable<Attempt<PublishStatus>> 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<Attempt<PublishStatus>>();
//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;
}
}
}
/// <summary>
@@ -1622,7 +1635,7 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional Id of the User issueing the publishing</param>
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise save events.</param>
/// <returns>True if publishing succeeded, otherwise False</returns>
private Attempt<PublishStatus> SaveAndPublishDo(IContent content, int userId = 0, bool raiseEvents = true)
private Attempt<PublishStatus> 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);
}
}
}
/// <summary>

View File

@@ -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<ContentXmlDto>()
.InnerJoin<NodeDto>()
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(dto => dto.NodeObjectType == Guid.Parse(Constants.ObjectTypes.Media));
.Where<NodeDto>(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<ContentXmlDto>()
.InnerJoin<NodeDto>()
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentDto>()
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType)
.Where<ContentDto>(dto => dto.ContentTypeId == id1);
var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
uow.Database.Execute(deleteSql);
}
}

View File

@@ -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<ContentXmlDto>()
.InnerJoin<NodeDto>()
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(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<ContentXmlDto>()
.InnerJoin<NodeDto>()
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentDto>()
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(dto => dto.NodeObjectType == memberObjectType)
.Where<ContentDto>(dto => dto.ContentTypeId == id1);
var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
uow.Database.Execute(deleteSql);
}
}

View File

@@ -31,6 +31,7 @@ namespace Umbraco.Tests.Persistence.SyntaxProvider
.InnerJoin<NodeDto>()
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(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