diff --git a/src/Umbraco.Core/IntExtensions.cs b/src/Umbraco.Core/IntExtensions.cs
index ffd2cc3a1b..ae2c01ef95 100644
--- a/src/Umbraco.Core/IntExtensions.cs
+++ b/src/Umbraco.Core/IntExtensions.cs
@@ -16,5 +16,17 @@ namespace Umbraco.Core
action(i);
}
}
+
+ ///
+ /// Creates a Guid based on an integer value
+ ///
+ /// value to convert
+ ///
+ public static Guid ToGuid(this int value)
+ {
+ byte[] bytes = new byte[16];
+ BitConverter.GetBytes(value).CopyTo(bytes, 0);
+ return new Guid(bytes);
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/EntityBase/Entity.cs b/src/Umbraco.Core/Models/EntityBase/Entity.cs
new file mode 100644
index 0000000000..d18c30c124
--- /dev/null
+++ b/src/Umbraco.Core/Models/EntityBase/Entity.cs
@@ -0,0 +1,221 @@
+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
+ {
+ private bool _hasIdentity;
+ private int? _hash;
+ private int _id;
+ private Guid _key;
+
+ ///
+ /// Integer Id
+ ///
+ [DataMember]
+ public int Id
+ {
+ get
+ {
+ return _id;
+ }
+ set
+ {
+ _id = 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.ToGuid();
+
+ return _key;
+ }
+ set { _key = value; }
+ }
+
+ ///
+ /// Gets or sets the Created Date
+ ///
+ [DataMember]
+ public DateTime CreatedDate { get; set; }
+
+ ///
+ /// Gets or sets the Modified Date
+ ///
+ [DataMember]
+ public DateTime ModifiedDate { 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));
+ }
+ }
+
+ ///
+ /// Method to call on entity saved when first added
+ ///
+ internal virtual void AddingEntity()
+ {
+ CreatedDate = DateTime.UtcNow;
+ ModifiedDate = DateTime.UtcNow;
+ }
+
+ ///
+ /// Method to call on entity saved/updated
+ ///
+ internal virtual void UpdatingEntity()
+ {
+ ModifiedDate = DateTime.UtcNow;
+ }
+
+ ///
+ /// Tracks the properties that have changed
+ ///
+ private readonly IDictionary _propertyChangedInfo = new Dictionary();
+
+ ///
+ /// Returns true if the property referenced by the name has been changed on the class
+ ///
+ ///
+ ///
+ public bool IsPropertyDirty(string propertyName)
+ {
+ return _propertyChangedInfo.Any(x => x.Key == propertyName);
+ }
+
+ ///
+ /// Returns true if any properties have been changed on the class
+ ///
+ ///
+ public bool IsDirty()
+ {
+ return _propertyChangedInfo.Any();
+ }
+
+ ///
+ /// Resets dirty properties by clearing the dictionary used to track changes.
+ ///
+ internal 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/EntityBase/IAggreateRoot.cs b/src/Umbraco.Core/Models/EntityBase/IAggreateRoot.cs
new file mode 100644
index 0000000000..4bbf151803
--- /dev/null
+++ b/src/Umbraco.Core/Models/EntityBase/IAggreateRoot.cs
@@ -0,0 +1,10 @@
+namespace Umbraco.Core.Models.EntityBase
+{
+ ///
+ /// Marker interface for aggregate roots
+ ///
+ public interface IAggreateRoot : IEntity
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/EntityBase/ICanBeDirty.cs b/src/Umbraco.Core/Models/EntityBase/ICanBeDirty.cs
new file mode 100644
index 0000000000..34dcc2d830
--- /dev/null
+++ b/src/Umbraco.Core/Models/EntityBase/ICanBeDirty.cs
@@ -0,0 +1,11 @@
+namespace Umbraco.Core.Models.EntityBase
+{
+ ///
+ /// An interface that defines the object is tracking property changes and if it is Dirty
+ ///
+ public interface ICanBeDirty
+ {
+ bool IsDirty();
+ bool IsPropertyDirty(string propName);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/EntityBase/IEntity.cs b/src/Umbraco.Core/Models/EntityBase/IEntity.cs
new file mode 100644
index 0000000000..2f0d81ee3f
--- /dev/null
+++ b/src/Umbraco.Core/Models/EntityBase/IEntity.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Umbraco.Core.Models.EntityBase
+{
+ ///
+ /// Defines an Entity.
+ /// Entities should always have an Id, Created and Modified date
+ ///
+ /// The current database schema doesn't provide a modified date
+ /// for all entities, so this will have to be changed at a later stage.
+ public interface IEntity
+ {
+ ///
+ /// The Id of the entity
+ ///
+ [DataMember]
+ int Id { get; set; }
+
+ ///
+ /// 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]
+ Guid Key { get; set; }
+
+ ///
+ /// Gets or sets the Created Date
+ ///
+ [DataMember]
+ DateTime CreatedDate { get; set; }
+
+ ///
+ /// Gets or sets the Modified Date
+ ///
+ [DataMember]
+ DateTime ModifiedDate { get; set; }
+
+ ///
+ /// Indicates whether the current entity has an identity, eg. Id.
+ ///
+ [IgnoreDataMember]
+ bool HasIdentity { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/EntityBase/IValueObject.cs b/src/Umbraco.Core/Models/EntityBase/IValueObject.cs
new file mode 100644
index 0000000000..3fb76e598e
--- /dev/null
+++ b/src/Umbraco.Core/Models/EntityBase/IValueObject.cs
@@ -0,0 +1,11 @@
+namespace Umbraco.Core.Models.EntityBase
+{
+ ///
+ /// Marker interface for value object, eg. objects without
+ /// the same kind of identity as an Entity (with its Id).
+ ///
+ public interface IValueObject
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index c19c511dd0..e37bb2f77f 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -37,6 +37,7 @@
+
@@ -91,6 +92,11 @@
+
+
+
+
+