diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 13d6bd71c9..f4af3b842e 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -460,10 +460,14 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (Content)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to manually clone this since it's not settable clone._contentType = (IContentType)ContentType.DeepClone(); + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 30ac526f4a..07c2067022 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -609,13 +609,18 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (ContentTypeBase)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to manually wire up the event handlers for the property type collections - we've ensured // its ignored from the auto-clone process because its return values are unions, not raw and // we end up with duplicates, see: http://issues.umbraco.org/issue/U4-4842 clone._propertyTypes = (PropertyTypeCollection)_propertyTypes.DeepClone(); clone._propertyTypes.CollectionChanged += clone.PropertyTypesChanged; + //this shouldn't really be needed since we're not tracking + clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; } diff --git a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs index ac358481f1..1fd1496742 100644 --- a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs @@ -255,11 +255,15 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (ContentTypeCompositionBase)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to manually assign since this is an internal field and will not be automatically mapped clone.RemovedContentTypeKeyTracker = new List(); clone._contentTypeComposition = ContentTypeComposition.Select(x => (IContentTypeComposition)x.DeepClone()).ToList(); + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; } diff --git a/src/Umbraco.Core/Models/EntityBase/Entity.cs b/src/Umbraco.Core/Models/EntityBase/Entity.cs index 315e2697c0..0ecdee2b54 100644 --- a/src/Umbraco.Core/Models/EntityBase/Entity.cs +++ b/src/Umbraco.Core/Models/EntityBase/Entity.cs @@ -236,9 +236,17 @@ namespace Umbraco.Core.Models.EntityBase //Memberwise clone on Entity will work since it doesn't have any deep elements // for any sub class this will work for standard properties as well that aren't complex object's themselves. var clone = (Entity)MemberwiseClone(); + //ensure the clone has it's own dictionaries + clone.ResetChangeTrackingCollections(); + //turn off change tracking + clone.DisableChangeTracking(); //Automatically deep clone ref properties that are IDeepCloneable DeepCloneHelper.DeepCloneRefProperties(this, clone); + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); + return clone; } } diff --git a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs index 2153b8f57f..7ab1b47ebb 100644 --- a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs +++ b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs @@ -18,7 +18,9 @@ namespace Umbraco.Core.Models.EntityBase public virtual IEnumerable GetDirtyProperties() { return _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key); - } + } + + private bool _changeTrackingEnabled = true; /// /// Tracks the properties that have changed @@ -41,6 +43,9 @@ namespace Umbraco.Core.Models.EntityBase /// The property info. protected virtual void OnPropertyChanged(PropertyInfo propertyInfo) { + //return if we're not tracking changes + if (_changeTrackingEnabled == false) return; + _propertyChangedInfo[propertyInfo.Name] = true; if (PropertyChanged != null) @@ -132,6 +137,22 @@ namespace Umbraco.Core.Models.EntityBase _propertyChangedInfo = new Dictionary(); } + protected void ResetChangeTrackingCollections() + { + _propertyChangedInfo = new Dictionary(); + _lastPropertyChangedInfo = new Dictionary(); + } + + protected void DisableChangeTracking() + { + _changeTrackingEnabled = false; + } + + protected void EnableChangeTracking() + { + _changeTrackingEnabled = true; + } + /// /// Used by inheritors to set the value of properties, this will detect if the property value actually changed and if it did /// it will ensure that the property has a dirty flag set. @@ -150,6 +171,9 @@ namespace Umbraco.Core.Models.EntityBase var initVal = value; var newVal = setValue(value); + //don't track changes, just set the value (above) + if (_changeTrackingEnabled == false) return false; + if (Equals(initVal, newVal) == false) { OnPropertyChanged(propertySelector); @@ -157,5 +181,7 @@ namespace Umbraco.Core.Models.EntityBase } return false; } + + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/File.cs b/src/Umbraco.Core/Models/File.cs index 3513e4e031..de32f6179c 100644 --- a/src/Umbraco.Core/Models/File.cs +++ b/src/Umbraco.Core/Models/File.cs @@ -113,12 +113,15 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (File)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to manually assign since they are readonly properties clone._alias = Alias; clone._name = Name; - + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; } diff --git a/src/Umbraco.Core/Models/Macro.cs b/src/Umbraco.Core/Models/Macro.cs index 0c86f5d1fe..fcc23ed858 100644 --- a/src/Umbraco.Core/Models/Macro.cs +++ b/src/Umbraco.Core/Models/Macro.cs @@ -399,14 +399,17 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (Macro)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); clone._addedProperties = new List(); clone._removedProperties = new List(); clone._properties = (MacroPropertyCollection)Properties.DeepClone(); //re-assign the event handler clone._properties.CollectionChanged += clone.PropertiesChanged; - + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; } diff --git a/src/Umbraco.Core/Models/Member.cs b/src/Umbraco.Core/Models/Member.cs index c4c0362acc..d416c846ef 100644 --- a/src/Umbraco.Core/Models/Member.cs +++ b/src/Umbraco.Core/Models/Member.cs @@ -617,10 +617,14 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (Member)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to manually clone this since it's not settable clone._contentType = (IMemberType)ContentType.DeepClone(); + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index c9b55bd937..1a4d06c8d9 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -415,15 +415,18 @@ namespace Umbraco.Core.Models.Membership public override object DeepClone() { var clone = (User)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to create new collections otherwise they'll get copied by ref clone._addedSections = new List(); clone._removedSections = new List(); clone._sectionCollection = new ObservableCollection(_sectionCollection.ToList()); //re-create the event handler clone._sectionCollection.CollectionChanged += clone.SectionCollectionChanged; - + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; } diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs index f8696794b1..4f8fa3deb2 100644 --- a/src/Umbraco.Core/Models/Property.cs +++ b/src/Umbraco.Core/Models/Property.cs @@ -160,10 +160,14 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (Property)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to manually assign since this is a readonly property clone._propertyType = (PropertyType)PropertyType.DeepClone(); + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; } diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index a19b7d98c2..5bf96d2578 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -456,14 +456,17 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (PropertyType)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to manually assign the Lazy value as it will not be automatically mapped if (PropertyGroupId != null) { clone._propertyGroupId = new Lazy(() => PropertyGroupId.Value); } - + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; } diff --git a/src/Umbraco.Core/Models/Template.cs b/src/Umbraco.Core/Models/Template.cs index fc10c818ef..72e546fcc3 100644 --- a/src/Umbraco.Core/Models/Template.cs +++ b/src/Umbraco.Core/Models/Template.cs @@ -193,12 +193,15 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (Template)base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //need to manually assign since they are readonly properties clone._alias = Alias; clone._name = Name; - + //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; } diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs index 23a6bcfe5b..4975ad3bd2 100644 --- a/src/Umbraco.Core/Models/UmbracoEntity.cs +++ b/src/Umbraco.Core/Models/UmbracoEntity.cs @@ -288,7 +288,8 @@ namespace Umbraco.Core.Models public override object DeepClone() { var clone = (UmbracoEntity) base.DeepClone(); - + //turn off change tracking + clone.DisableChangeTracking(); //This ensures that any value in the dictionary that is deep cloneable is cloned too foreach (var key in clone.AdditionalData.Keys.ToArray()) { @@ -298,7 +299,10 @@ namespace Umbraco.Core.Models clone.AdditionalData[key] = deepCloneable.DeepClone(); } } - + //this shouldn't really be needed since we're not tracking + clone.ResetDirtyProperties(false); + //re-enable tracking + clone.EnableChangeTracking(); return clone; }