diff --git a/src/Umbraco.Core/Models/ContentType.cs b/src/Umbraco.Core/Models/ContentType.cs
index 710efb9e3a..5fb1fa3100 100644
--- a/src/Umbraco.Core/Models/ContentType.cs
+++ b/src/Umbraco.Core/Models/ContentType.cs
@@ -143,35 +143,19 @@ namespace Umbraco.Core.Models
}
///
- /// //TODO: REmove this as it's mostly just a shallow clone and not thread safe
- /// Creates a clone of the current entity
+ /// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
///
///
public IContentType Clone(string alias)
{
- var clone = (ContentType)this.MemberwiseClone();
+ var clone = (ContentType)DeepClone();
clone.Alias = alias;
clone.Key = Guid.Empty;
- var propertyGroups = this.PropertyGroups.Select(x => x.Clone()).ToList();
+ var propertyGroups = PropertyGroups.Select(x => x.Clone()).ToList();
clone.PropertyGroups = new PropertyGroupCollection(propertyGroups);
- clone.PropertyTypes = this.PropertyTypeCollection.Select(x => x.Clone()).ToList();
+ clone.PropertyTypes = PropertyTypeCollection.Select(x => x.Clone()).ToList();
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
-
- foreach (var propertyGroup in clone.PropertyGroups)
- {
- propertyGroup.ResetIdentity();
- foreach (var propertyType in propertyGroup.PropertyTypes)
- {
- propertyType.ResetIdentity();
- }
- }
-
- foreach (var propertyType in clone.PropertyTypes.Where(x => x.HasIdentity))
- {
- propertyType.ResetIdentity();
- }
-
return clone;
}
diff --git a/src/Umbraco.Core/Models/PropertyGroup.cs b/src/Umbraco.Core/Models/PropertyGroup.cs
index 3158dfe6d6..b432cced08 100644
--- a/src/Umbraco.Core/Models/PropertyGroup.cs
+++ b/src/Umbraco.Core/Models/PropertyGroup.cs
@@ -143,16 +143,17 @@ namespace Umbraco.Core.Models
return hashName ^ hashId;
}
- //TODO: Remove this, its mostly a shallow clone and is not thread safe
+ ///
+ /// Creates a deep clone of the current entity with its identity and it's property identities reset
+ ///
+ ///
internal PropertyGroup Clone()
{
- var clone = (PropertyGroup)this.MemberwiseClone();
+ var clone = (PropertyGroup)DeepClone();
var collection = new PropertyTypeCollection();
- foreach (var propertyType in this.PropertyTypes)
+ foreach (var propertyType in PropertyTypes)
{
- var property = propertyType.Clone();
- property.ResetIdentity();
- property.ResetDirtyProperties(false);
+ var property = propertyType.Clone();
collection.Add(property);
}
clone.PropertyTypes = collection;
diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs
index 83a8c09a99..f59a79748f 100644
--- a/src/Umbraco.Core/Models/PropertyType.cs
+++ b/src/Umbraco.Core/Models/PropertyType.cs
@@ -443,10 +443,13 @@ namespace Umbraco.Core.Models
return hashName ^ hashAlias;
}
- //TODO: Remove this
+ ///
+ /// Creates a deep clone of the current entity with its identity and it's property identities reset
+ ///
+ ///
internal PropertyType Clone()
{
- var clone = (PropertyType)this.MemberwiseClone();
+ var clone = (PropertyType)DeepClone();
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
diff --git a/src/Umbraco.Tests/Models/ContentTypeTests.cs b/src/Umbraco.Tests/Models/ContentTypeTests.cs
index af94f80fd4..0fc1a52a28 100644
--- a/src/Umbraco.Tests/Models/ContentTypeTests.cs
+++ b/src/Umbraco.Tests/Models/ContentTypeTests.cs
@@ -24,6 +24,69 @@ namespace Umbraco.Tests.Models
}
+ [Test]
+ public void Can_Deep_Clone_Content_Type_With_Reset_Identities()
+ {
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ contentType.Id = 99;
+
+ var i = 200;
+ foreach (var propertyType in contentType.PropertyTypes)
+ {
+ propertyType.Id = ++i;
+ }
+ foreach (var group in contentType.PropertyGroups)
+ {
+ group.Id = ++i;
+ }
+ //add a property type without a property group
+ contentType.PropertyTypeCollection.Add(
+ new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "title2", Name = "Title2", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 });
+
+ contentType.AllowedTemplates = new[] { new Template("-1,2", "Name", "name") { Id = 200 }, new Template("-1,3", "Name2", "name2") { Id = 201 } };
+ contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy(() => 888), 8, "sub"), new ContentTypeSort(new Lazy(() => 889), 9, "sub2") };
+ contentType.Id = 10;
+ contentType.CreateDate = DateTime.Now;
+ contentType.CreatorId = 22;
+ contentType.SetDefaultTemplate(new Template("-1,2,3,4", "Test Template", "testTemplate")
+ {
+ Id = 88
+ });
+ contentType.Description = "test";
+ contentType.Icon = "icon";
+ contentType.IsContainer = true;
+ contentType.Thumbnail = "thumb";
+ contentType.Key = Guid.NewGuid();
+ contentType.Level = 3;
+ contentType.Path = "-1,4,10";
+ contentType.SortOrder = 5;
+ contentType.Trashed = false;
+ contentType.UpdateDate = DateTime.Now;
+
+ //ensure that nothing is marked as dirty
+ contentType.ResetDirtyProperties(false);
+
+ var clone = (ContentType)contentType.Clone("newAlias");
+
+ Assert.AreEqual("newAlias", clone.Alias);
+ Assert.AreNotEqual("newAlias", contentType.Alias);
+ Assert.IsFalse(clone.HasIdentity);
+
+ foreach (var propertyGroup in clone.PropertyGroups)
+ {
+ Assert.IsFalse(propertyGroup.HasIdentity);
+ foreach (var propertyType in propertyGroup.PropertyTypes)
+ {
+ Assert.IsFalse(propertyType.HasIdentity);
+ }
+ }
+
+ foreach (var propertyType in clone.PropertyTypes.Where(x => x.HasIdentity))
+ {
+ Assert.IsFalse(propertyType.HasIdentity);
+ }
+ }
+
[Test]
public void Can_Deep_Clone_Content_Type()
{
@@ -36,6 +99,10 @@ namespace Umbraco.Tests.Models
{
propertyType.Id = ++i;
}
+ foreach (var group in contentType.PropertyGroups)
+ {
+ group.Id = ++i;
+ }
contentType.AllowedTemplates = new[] { new Template("-1,2", "Name", "name") { Id = 200 }, new Template("-1,3", "Name2", "name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] {new ContentTypeSort(new Lazy(() => 888), 8, "sub"), new ContentTypeSort(new Lazy(() => 889), 9, "sub2")};
contentType.Id = 10;