using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Runtime.Serialization; namespace Umbraco.Core.Models.EntityBase { /// /// Base Abstract Entity /// [Serializable] [DataContract(IsReference = true)] public abstract class Entity : IEntity, ICanBeDirty { private bool _hasIdentity; private int? _hash; private Lazy _id; private Guid _key; /// /// Integer Id /// [DataMember] public int Id { get { return _id == null ? default(int) : _id.Value; } set { _id = new Lazy(() => value); HasIdentity = true; } } /// /// Guid based Id /// /// The key is currectly used to store the Unique Id from the /// umbracoNode table, which many of the entities are based on. [DataMember] public Guid Key { get { if (_key == Guid.Empty) return _id.Value.ToGuid(); return _key; } set { _key = value; } } /// /// Gets or sets the Created Date /// [DataMember] public DateTime CreateDate { get; set; } /// /// Gets or sets the Modified Date /// [DataMember] public DateTime UpdateDate { get; set; } /// /// Property changed event /// public event PropertyChangedEventHandler PropertyChanged; /// /// Method to call on a property setter. /// /// The property info. protected virtual void OnPropertyChanged(PropertyInfo propertyInfo) { _propertyChangedInfo[propertyInfo.Name] = true; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name)); } } protected void ResetIdentity() { _hasIdentity = false; _id = new Lazy(() => default(int)); } /// /// Method to call on entity saved when first added /// internal virtual void AddingEntity() { CreateDate = DateTime.UtcNow; UpdateDate = DateTime.UtcNow; } /// /// Method to call on entity saved/updated /// internal virtual void UpdatingEntity() { UpdateDate = DateTime.UtcNow; } /// /// Tracks the properties that have changed /// private readonly IDictionary _propertyChangedInfo = new Dictionary(); /// /// Indicates whether a specific property on the current entity is dirty. /// /// Name of the property to check /// True if Property is dirty, otherwise False public virtual bool IsPropertyDirty(string propertyName) { return _propertyChangedInfo.Any(x => x.Key == propertyName); } /// /// Indicates whether the current entity is dirty. /// /// True if entity is dirty, otherwise False public virtual bool IsDirty() { return _propertyChangedInfo.Any(); } /// /// Resets dirty properties by clearing the dictionary used to track changes. /// /// /// Please note that resetting the dirty properties could potentially /// obstruct the saving of a new or updated entity. /// public virtual void ResetDirtyProperties() { _propertyChangedInfo.Clear(); } /// /// Indicates whether the current entity has an identity, eg. Id. /// public virtual bool HasIdentity { get { return _hasIdentity; } protected set { _hasIdentity = value; } } public static bool operator ==(Entity left, Entity right) { if (ReferenceEquals(null, left)) return false; return left.Equals(right); } public static bool operator !=(Entity left, Entity right) { return !(left == right); } public virtual bool SameIdentityAs(IEntity other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return SameIdentityAs(other as Entity); } public virtual bool Equals(Entity other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return SameIdentityAs(other); } public virtual Type GetRealType() { return GetType(); } public virtual bool SameIdentityAs(Entity other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; if (GetType() == other.GetRealType() && HasIdentity && other.HasIdentity) return other.Id.Equals(Id); return false; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; return SameIdentityAs(obj as IEntity); } public override int GetHashCode() { if (!_hash.HasValue) _hash = !HasIdentity ? new int?(base.GetHashCode()) : new int?(Id.GetHashCode() * 397 ^ GetType().GetHashCode()); return _hash.Value; } } }