diff --git a/src/Umbraco.Abstractions/Collections/DeepCloneableList.cs b/src/Umbraco.Abstractions/Collections/DeepCloneableList.cs index cc57b96f1b..b682e20358 100644 --- a/src/Umbraco.Abstractions/Collections/DeepCloneableList.cs +++ b/src/Umbraco.Abstractions/Collections/DeepCloneableList.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -80,6 +81,7 @@ namespace Umbraco.Core.Collections } } + #region IRememberBeingDirty public bool IsDirty() { return this.OfType().Any(x => x.IsDirty()); @@ -150,5 +152,8 @@ namespace Umbraco.Core.Collections { return Enumerable.Empty(); } + + public event PropertyChangedEventHandler PropertyChanged; // noop + #endregion } } diff --git a/src/Umbraco.Abstractions/Models/Entities/EntitySlim.cs b/src/Umbraco.Abstractions/Models/Entities/EntitySlim.cs index c25f6b533e..b6983773b1 100644 --- a/src/Umbraco.Abstractions/Models/Entities/EntitySlim.cs +++ b/src/Umbraco.Abstractions/Models/Entities/EntitySlim.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Runtime.Serialization; using Umbraco.Core.Exceptions; @@ -23,7 +24,7 @@ namespace Umbraco.Core.Models.Entities /// Gets an entity representing "root". /// public static readonly IEntitySlim Root = new EntitySlim { Path = "-1", Name = "root", HasChildren = true }; - + // implement IEntity /// @@ -121,72 +122,10 @@ namespace Umbraco.Core.Models.Entities #endregion - #region IRememberBeingDirty - - // IEntitySlim does *not* track changes, but since it indirectly implements IUmbracoEntity, - // and therefore IRememberBeingDirty, we have to have those methods - which all throw. - - public bool IsDirty() - { - throw new WontImplementException(); - } - - public bool IsPropertyDirty(string propName) - { - throw new WontImplementException(); - } - - public IEnumerable GetDirtyProperties() - { - throw new WontImplementException(); - } - - public void ResetDirtyProperties() - { - throw new WontImplementException(); - } - - public void DisableChangeTracking() - { - // noop - } - - public void EnableChangeTracking() - { - // noop - } - - public bool WasDirty() - { - throw new WontImplementException(); - } - - public bool WasPropertyDirty(string propertyName) - { - throw new WontImplementException(); - } - - public void ResetWereDirtyProperties() - { - throw new WontImplementException(); - } - - public void ResetDirtyProperties(bool rememberDirty) - { - throw new WontImplementException(); - } - - public IEnumerable GetWereDirtyProperties() - { - throw new WontImplementException(); - } - public void ResetIdentity() { Id = default; Key = Guid.Empty; } - - #endregion } } diff --git a/src/Umbraco.Abstractions/Models/Entities/ICanBeDirty.cs b/src/Umbraco.Abstractions/Models/Entities/ICanBeDirty.cs index 57a8a581f0..03e2f19c70 100644 --- a/src/Umbraco.Abstractions/Models/Entities/ICanBeDirty.cs +++ b/src/Umbraco.Abstractions/Models/Entities/ICanBeDirty.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel; namespace Umbraco.Core.Models.Entities { @@ -36,5 +37,7 @@ namespace Umbraco.Core.Models.Entities /// Enables change tracking. /// void EnableChangeTracking(); + + event PropertyChangedEventHandler PropertyChanged; } } diff --git a/src/Umbraco.Abstractions/Models/Entities/IUmbracoEntity.cs b/src/Umbraco.Abstractions/Models/Entities/IUmbracoEntity.cs index e5f628b098..f76ec2438a 100644 --- a/src/Umbraco.Abstractions/Models/Entities/IUmbracoEntity.cs +++ b/src/Umbraco.Abstractions/Models/Entities/IUmbracoEntity.cs @@ -2,6 +2,7 @@ namespace Umbraco.Core.Models.Entities { + /// /// Represents an entity that can be managed by the entity service. /// @@ -10,6 +11,6 @@ namespace Umbraco.Core.Models.Entities /// IUmbracoEntities can be retrieved with the IEntityService. /// An IUmbracoEntity can participate in notifications. /// - public interface IUmbracoEntity : ITreeEntity, IRememberBeingDirty + public interface IUmbracoEntity : ITreeEntity { } } diff --git a/src/Umbraco.Abstractions/Models/IContentBase.cs b/src/Umbraco.Abstractions/Models/IContentBase.cs index 1864996379..1aade803b8 100644 --- a/src/Umbraco.Abstractions/Models/IContentBase.cs +++ b/src/Umbraco.Abstractions/Models/IContentBase.cs @@ -11,7 +11,7 @@ namespace Umbraco.Core.Models /// Content items are documents, medias and members. /// Content items have a content type, and properties. /// - public interface IContentBase : IUmbracoEntity + public interface IContentBase : IUmbracoEntity, IRememberBeingDirty { /// /// Integer Id of the default ContentType diff --git a/src/Umbraco.Abstractions/Models/IContentTypeBase.cs b/src/Umbraco.Abstractions/Models/IContentTypeBase.cs index 03ea0b5427..d65e2dcdfb 100644 --- a/src/Umbraco.Abstractions/Models/IContentTypeBase.cs +++ b/src/Umbraco.Abstractions/Models/IContentTypeBase.cs @@ -8,7 +8,7 @@ namespace Umbraco.Core.Models /// Defines the base for a ContentType with properties that /// are shared between ContentTypes and MediaTypes. /// - public interface IContentTypeBase : IUmbracoEntity + public interface IContentTypeBase : IUmbracoEntity, IRememberBeingDirty { /// /// Gets or Sets the Alias of the ContentType diff --git a/src/Umbraco.Abstractions/Models/IDataType.cs b/src/Umbraco.Abstractions/Models/IDataType.cs index c7e682e4a2..39278abdc1 100644 --- a/src/Umbraco.Abstractions/Models/IDataType.cs +++ b/src/Umbraco.Abstractions/Models/IDataType.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Models /// /// Represents a data type. /// - public interface IDataType : IUmbracoEntity + public interface IDataType : IUmbracoEntity, IRememberBeingDirty { /// /// Gets or sets the property editor. diff --git a/src/Umbraco.Abstractions/Models/IDictionaryTranslation.cs b/src/Umbraco.Abstractions/Models/IDictionaryTranslation.cs index 5cbec40b81..8510e5c520 100644 --- a/src/Umbraco.Abstractions/Models/IDictionaryTranslation.cs +++ b/src/Umbraco.Abstractions/Models/IDictionaryTranslation.cs @@ -3,7 +3,7 @@ using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models { - public interface IDictionaryTranslation : IEntity + public interface IDictionaryTranslation : IEntity, IRememberBeingDirty { /// /// Gets or sets the for the translation diff --git a/src/Umbraco.Abstractions/Models/IFile.cs b/src/Umbraco.Abstractions/Models/IFile.cs index 0d98c90ffb..835c9bf434 100644 --- a/src/Umbraco.Abstractions/Models/IFile.cs +++ b/src/Umbraco.Abstractions/Models/IFile.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.Models /// Defines a File /// /// Used for Scripts, Stylesheets and Templates - public interface IFile : IEntity + public interface IFile : IEntity, IRememberBeingDirty { /// /// Gets the Name of the File including extension diff --git a/src/Umbraco.Abstractions/Models/IPropertyType.cs b/src/Umbraco.Abstractions/Models/IPropertyType.cs index ca288ad0b2..7c455d3ba5 100644 --- a/src/Umbraco.Abstractions/Models/IPropertyType.cs +++ b/src/Umbraco.Abstractions/Models/IPropertyType.cs @@ -84,7 +84,5 @@ namespace Umbraco.Core.Models /// Throws if the value cannot be converted. /// object ConvertAssignedValue(object value); - - event PropertyChangedEventHandler PropertyChanged; } } diff --git a/src/Umbraco.Abstractions/Models/ISimpleContentType.cs b/src/Umbraco.Abstractions/Models/ISimpleContentType.cs index 740db8e73f..52364cfa1e 100644 --- a/src/Umbraco.Abstractions/Models/ISimpleContentType.cs +++ b/src/Umbraco.Abstractions/Models/ISimpleContentType.cs @@ -1,14 +1,15 @@ -using Umbraco.Core.Models.Entities; +using System; namespace Umbraco.Core.Models { /// /// Represents a simplified view of a content type. /// - public interface ISimpleContentType : IUmbracoEntity + public interface ISimpleContentType { - new int Id { get; } - new string Name { get; } + int Id { get; } + Guid Key { get; } + string Name { get; } /// /// Gets the alias of the content type. diff --git a/src/Umbraco.Abstractions/Models/IStylesheet.cs b/src/Umbraco.Abstractions/Models/IStylesheet.cs index 737118d646..bc2d870ea4 100644 --- a/src/Umbraco.Abstractions/Models/IStylesheet.cs +++ b/src/Umbraco.Abstractions/Models/IStylesheet.cs @@ -3,7 +3,7 @@ using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models { - public interface IStylesheet : IFile, IRememberBeingDirty + public interface IStylesheet : IFile { /// /// Returns a list of umbraco back office enabled stylesheet properties diff --git a/src/Umbraco.Abstractions/Models/MacroProperty.cs b/src/Umbraco.Abstractions/Models/MacroProperty.cs index 9dfb81cf71..6714baf17b 100644 --- a/src/Umbraco.Abstractions/Models/MacroProperty.cs +++ b/src/Umbraco.Abstractions/Models/MacroProperty.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Models /// [Serializable] [DataContract(IsReference = true)] - public class MacroProperty : BeingDirtyBase, IMacroProperty, IRememberBeingDirty, IDeepCloneable + public class MacroProperty : BeingDirtyBase, IMacroProperty { public MacroProperty() { diff --git a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs index 51c642c20d..121fb7a5d1 100644 --- a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs @@ -44,16 +44,13 @@ namespace Umbraco.Core.Models // property variation change? var hasAnyPropertyVariationChanged = contentType.PropertyTypes.Any(propertyType => { - if (!(propertyType is IRememberBeingDirty dirtyProperty)) - throw new Exception("oops"); - // skip new properties // TODO: This used to be WasPropertyDirty("HasIdentity") but i don't think that actually worked for detecting new entities this does seem to work properly - var isNewProperty = dirtyProperty.WasPropertyDirty("Id"); + var isNewProperty = propertyType.WasPropertyDirty("Id"); if (isNewProperty) return false; // variation change? - var dirty = dirtyProperty.WasPropertyDirty("Variations"); + var dirty = propertyType.WasPropertyDirty("Variations"); if (dirty) a.Add(propertyType.Alias); diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index 8dc056d555..7e42a526b0 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; using System.Linq; using Umbraco.Core.Composing; using Umbraco.Core.Models.Entities; @@ -403,6 +404,18 @@ namespace Umbraco.Core.Models.Identity _beingDirty.EnableChangeTracking(); } + public event PropertyChangedEventHandler PropertyChanged + { + add + { + _beingDirty.PropertyChanged += value; + } + remove + { + _beingDirty.PropertyChanged -= value; + } + } + #endregion //Custom comparer for enumerables @@ -413,5 +426,6 @@ namespace Umbraco.Core.Models.Identity private static readonly DelegateEqualityComparer StartIdsComparer = new DelegateEqualityComparer( (groups, enumerable) => groups.UnsortedSequenceEqual(enumerable), groups => groups.GetHashCode()); + } } diff --git a/src/Umbraco.Core/Models/SimpleContentType.cs b/src/Umbraco.Core/Models/SimpleContentType.cs index e3fde764cb..dde8450d90 100644 --- a/src/Umbraco.Core/Models/SimpleContentType.cs +++ b/src/Umbraco.Core/Models/SimpleContentType.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models { @@ -37,6 +35,7 @@ namespace Umbraco.Core.Models if (contentType == null) throw new ArgumentNullException(nameof(contentType)); Id = contentType.Id; + Key = contentType.Key; Alias = contentType.Alias; Variations = contentType.Variations; Icon = contentType.Icon; @@ -46,32 +45,26 @@ namespace Umbraco.Core.Models IsElement = contentType.IsElement; } - /// public string Alias { get; } public int Id { get; } - /// + public Guid Key { get; } + public ITemplate DefaultTemplate { get; } - /// public ContentVariation Variations { get; } - /// public string Icon { get; } - /// public bool IsContainer { get; } public string Name { get; } - /// public bool AllowedAsRoot { get; } - /// public bool IsElement { get; } - /// public bool SupportsPropertyVariation(string culture, string segment, bool wildcards = false) { // non-exact validation: can accept a 'null' culture if the property type varies @@ -85,7 +78,6 @@ namespace Umbraco.Core.Models return string.Equals(Alias, other.Alias) && Id == other.Id; } - /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; @@ -94,7 +86,6 @@ namespace Umbraco.Core.Models return Equals((SimpleContentType) obj); } - /// public override int GetHashCode() { unchecked @@ -102,37 +93,5 @@ namespace Umbraco.Core.Models return ((Alias != null ? Alias.GetHashCode() : 0) * 397) ^ Id; } } - - // we have to have all this, because we're an IUmbracoEntity, because that is - // required by the query expression visitor / SimpleContentTypeMapper - // TODO: Make the query expression visitor use a different common interface, or investigate removing IRememberBeingDirty from being a requirement on that interface and expliclty checking for that throughout the code? - - string ITreeEntity.Name { get => this.Name; set => throw new NotImplementedException(); } - int IEntity.Id { get => this.Id; set => throw new NotImplementedException(); } - bool IEntity.HasIdentity => this.Id != default; - void IEntity.ResetIdentity() => throw new NotImplementedException(); - int ITreeEntity.CreatorId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - int ITreeEntity.ParentId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - int ITreeEntity.Level { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - string ITreeEntity.Path { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - int ITreeEntity.SortOrder { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - bool ITreeEntity.Trashed => throw new NotImplementedException(); - Guid IEntity.Key { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - DateTime IEntity.CreateDate { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - DateTime IEntity.UpdateDate { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - DateTime? IEntity.DeleteDate { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - void ITreeEntity.SetParent(ITreeEntity parent) => throw new NotImplementedException(); - object IDeepCloneable.DeepClone() => throw new NotImplementedException(); - bool IRememberBeingDirty.WasDirty() => throw new NotImplementedException(); - bool IRememberBeingDirty.WasPropertyDirty(string propertyName) => throw new NotImplementedException(); - void IRememberBeingDirty.ResetWereDirtyProperties() => throw new NotImplementedException(); - void IRememberBeingDirty.ResetDirtyProperties(bool rememberDirty) => throw new NotImplementedException(); - IEnumerable IRememberBeingDirty.GetWereDirtyProperties() => throw new NotImplementedException(); - bool ICanBeDirty.IsDirty() => throw new NotImplementedException(); - bool ICanBeDirty.IsPropertyDirty(string propName) => throw new NotImplementedException(); - IEnumerable ICanBeDirty.GetDirtyProperties() => throw new NotImplementedException(); - void ICanBeDirty.ResetDirtyProperties() => throw new NotImplementedException(); - public void DisableChangeTracking() => throw new NotImplementedException(); - public void EnableChangeTracking() => throw new NotImplementedException(); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/IMapperCollection.cs b/src/Umbraco.Core/Persistence/Mappers/IMapperCollection.cs index dfa6a7ca5b..62d35c3eb8 100644 --- a/src/Umbraco.Core/Persistence/Mappers/IMapperCollection.cs +++ b/src/Umbraco.Core/Persistence/Mappers/IMapperCollection.cs @@ -5,6 +5,7 @@ namespace Umbraco.Core.Persistence.Mappers { public interface IMapperCollection : IBuilderCollection { + bool TryGetMapper(Type type, out BaseMapper mapper); BaseMapper this[Type type] { get; } } } diff --git a/src/Umbraco.Core/Persistence/Mappers/MapperCollection.cs b/src/Umbraco.Core/Persistence/Mappers/MapperCollection.cs index 343406378a..20929dd188 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MapperCollection.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MapperCollection.cs @@ -10,27 +10,40 @@ namespace Umbraco.Core.Persistence.Mappers { public MapperCollection(IEnumerable items) : base(items) - { } + { - // maintain our own index for faster lookup - private readonly ConcurrentDictionary _index = new ConcurrentDictionary(); + _index = new Lazy>(() => + { + var d = new ConcurrentDictionary(); + foreach(var mapper in this) + { + var attributes = mapper.GetType().GetCustomAttributes(false); + foreach(var a in attributes) + { + d.TryAdd(a.EntityType, mapper); + } + } + return d; + }); + } + private readonly Lazy> _index; + + /// + /// Returns a mapper for this type, throw an exception if not found + /// + /// + /// public BaseMapper this[Type type] { get { - return _index.GetOrAdd(type, t => - { - // check if any of the mappers are assigned to this type - var mapper = this.FirstOrDefault(x => x.GetType() - .GetCustomAttributes(false) - .Any(m => m.EntityType == type)); - - if (mapper != null) return mapper; - - throw new Exception($"Could not find a mapper matching type {type.FullName}."); - }); + if (_index.Value.TryGetValue(type, out var mapper)) + return mapper; + throw new Exception($"Could not find a mapper matching type {type.FullName}."); } } + + public bool TryGetMapper(Type type, out BaseMapper mapper) => _index.Value.TryGetValue(type, out mapper); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/SimpleContentTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/SimpleContentTypeMapper.cs deleted file mode 100644 index f98ff3b694..0000000000 --- a/src/Umbraco.Core/Persistence/Mappers/SimpleContentTypeMapper.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Concurrent; -using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Dtos; - -namespace Umbraco.Core.Persistence.Mappers -{ - [MapperFor(typeof(ISimpleContentType))] - [MapperFor(typeof(SimpleContentType))] - public sealed class SimpleContentTypeMapper : BaseMapper - { - public SimpleContentTypeMapper(Lazy sqlContext, ConcurrentDictionary> maps) - : base(sqlContext, maps) - { } - - protected override void DefineMaps() - { - DefineMap(nameof(ContentType.Id), nameof(NodeDto.NodeId)); - DefineMap(nameof(ContentType.CreateDate), nameof(NodeDto.CreateDate)); - DefineMap(nameof(ContentType.Level), nameof(NodeDto.Level)); - DefineMap(nameof(ContentType.ParentId), nameof(NodeDto.ParentId)); - DefineMap(nameof(ContentType.Path), nameof(NodeDto.Path)); - DefineMap(nameof(ContentType.SortOrder), nameof(NodeDto.SortOrder)); - DefineMap(nameof(ContentType.Name), nameof(NodeDto.Text)); - DefineMap(nameof(ContentType.Trashed), nameof(NodeDto.Trashed)); - DefineMap(nameof(ContentType.Key), nameof(NodeDto.UniqueId)); - DefineMap(nameof(ContentType.CreatorId), nameof(NodeDto.UserId)); - DefineMap(nameof(ContentType.Alias), nameof(ContentTypeDto.Alias)); - DefineMap(nameof(ContentType.AllowedAsRoot), nameof(ContentTypeDto.AllowAtRoot)); - DefineMap(nameof(ContentType.Description), nameof(ContentTypeDto.Description)); - DefineMap(nameof(ContentType.Icon), nameof(ContentTypeDto.Icon)); - DefineMap(nameof(ContentType.IsContainer), nameof(ContentTypeDto.IsContainer)); - DefineMap(nameof(ContentType.IsElement), nameof(ContentTypeDto.IsElement)); - DefineMap(nameof(ContentType.Thumbnail), nameof(ContentTypeDto.Thumbnail)); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionVisitor.cs b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionVisitor.cs index c87937e41e..7ff536caba 100644 --- a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionVisitor.cs +++ b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionVisitor.cs @@ -60,8 +60,8 @@ namespace Umbraco.Core.Persistence.Querying if (m.Expression != null && m.Expression.Type != typeof(T) - && TypeHelper.IsTypeAssignableFrom(m.Expression.Type) //TODO: Could this just be `IEntity` ? why does it need to be IUmbracoEntity, we aren't even using the reference to that below - && EndsWithConstant(m) == false) + && EndsWithConstant(m) == false + && _mappers.TryGetMapper(m.Expression.Type, out var subMapper)) { //if this is the case, it means we have a sub expression / nested property access, such as: x.ContentType.Alias == "Test"; //and since the sub type (x.ContentType) is not the same as x, we need to resolve a mapper for x.ContentType to get it's mapped SQL column @@ -69,7 +69,6 @@ namespace Umbraco.Core.Persistence.Querying //don't execute if compiled if (Visited == false) { - var subMapper = _mappers[m.Expression.Type]; // throws if not found var field = subMapper.Map(m.Member.Name); if (field.IsNullOrWhiteSpace()) throw new InvalidOperationException($"The mapper returned an empty field for the member name: {m.Member.Name} for type: {m.Expression.Type}"); diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index 705a876d83..ad10a1371b 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -148,16 +148,13 @@ namespace Umbraco.Core.Services.Implement // existing property alias change? var hasAnyPropertyChangedAlias = contentType.PropertyTypes.Any(propertyType => { - if (!(propertyType is IRememberBeingDirty dirtyProperty)) - throw new Exception("oops"); - // skip new properties // TODO: This used to be WasPropertyDirty("HasIdentity") but i don't think that actually worked for detecting new entities this does seem to work properly - var isNewProperty = dirtyProperty.WasPropertyDirty("Id"); + var isNewProperty = propertyType.WasPropertyDirty("Id"); if (isNewProperty) return false; // alias change? - return dirtyProperty.WasPropertyDirty("Alias"); + return propertyType.WasPropertyDirty("Alias"); }); // removed properties? diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 49011993e3..18dd60fd40 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -343,7 +343,6 @@ -