Files
Umbraco-CMS/src/Umbraco.Core/Models/PropertyGroup.cs
Dennis 7208f591c7 Fix equality check on property group (#13133)
* Fix equality check on property group

Also fix circular reference on PropertyTypeCollection

(cherry picked from commit f64f634979)
2023-03-28 10:08:48 +02:00

159 lines
4.7 KiB
C#

using System.Collections.Specialized;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using Umbraco.Cms.Core.Models.Entities;
namespace Umbraco.Cms.Core.Models;
/// <summary>
/// Represents a group of property types.
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")]
public class PropertyGroup : EntityBase, IEquatable<PropertyGroup>
{
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "This field is for internal use only (to allow changing item keys).")]
internal PropertyGroupCollection? Collection;
private string _alias;
private string? _name;
private PropertyTypeCollection? _propertyTypes;
private int _sortOrder;
private PropertyGroupType _type;
public PropertyGroup(bool isPublishing)
: this(new PropertyTypeCollection(isPublishing))
{
}
public PropertyGroup(PropertyTypeCollection propertyTypeCollection)
{
PropertyTypes = propertyTypeCollection;
_alias = string.Empty;
}
/// <summary>
/// Gets or sets the type of the group.
/// </summary>
/// <value>
/// The type.
/// </value>
[DataMember]
public PropertyGroupType Type
{
get => _type;
set => SetPropertyValueAndDetectChanges(value, ref _type, nameof(Type));
}
/// <summary>
/// Gets or sets the name of the group.
/// </summary>
/// <value>
/// The name.
/// </value>
[DataMember]
public string? Name
{
get => _name;
set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name));
}
/// <summary>
/// Gets or sets the alias of the group.
/// </summary>
/// <value>
/// The alias.
/// </value>
[DataMember]
public string Alias
{
get => _alias;
set
{
// If added to a collection, ensure the key is changed before setting it (this ensures the internal lookup dictionary is updated)
Collection?.ChangeKey(this, value);
SetPropertyValueAndDetectChanges(value, ref _alias!, nameof(Alias));
}
}
/// <summary>
/// Gets or sets the sort order of the group.
/// </summary>
/// <value>
/// The sort order.
/// </value>
[DataMember]
public int SortOrder
{
get => _sortOrder;
set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, nameof(SortOrder));
}
/// <summary>
/// Gets or sets a collection of property types for the group.
/// </summary>
/// <value>
/// The property types.
/// </value>
/// <remarks>
/// Marked with DoNotClone, because we will manually deal with cloning and the event handlers.
/// </remarks>
[DataMember]
[DoNotClone]
public PropertyTypeCollection? PropertyTypes
{
get => _propertyTypes;
set
{
if (_propertyTypes != null)
{
_propertyTypes.ClearCollectionChangedEvents();
}
_propertyTypes = value;
if (_propertyTypes is not null)
{
// since we're adding this collection to this group,
// we need to ensure that all the lazy values are set.
foreach (IPropertyType propertyType in _propertyTypes)
{
propertyType.PropertyGroupId = new Lazy<int>(() => Id);
}
OnPropertyChanged(nameof(PropertyTypes));
_propertyTypes.CollectionChanged += PropertyTypesChanged;
}
}
}
public bool Equals(PropertyGroup? other) =>
base.Equals(other) || (other != null && Type == other.Type && Alias == other.Alias && Id == other.Id);
public override int GetHashCode() => (base.GetHashCode(), Type, Alias).GetHashCode();
protected override void PerformDeepClone(object clone)
{
base.PerformDeepClone(clone);
var clonedEntity = (PropertyGroup)clone;
clonedEntity.Collection = null;
if (clonedEntity._propertyTypes != null)
{
clonedEntity._propertyTypes.ClearCollectionChangedEvents(); // clear this event handler if any
clonedEntity._propertyTypes = (PropertyTypeCollection)_propertyTypes!.DeepClone(); // manually deep clone
clonedEntity._propertyTypes.CollectionChanged +=
clonedEntity.PropertyTypesChanged; // re-assign correct event handler
}
}
private void PropertyTypesChanged(object? sender, NotifyCollectionChangedEventArgs e) =>
OnPropertyChanged(nameof(PropertyTypes));
}