Browse Source

Added Entity and ValueObject classes.

pull/81/head
Halil İbrahim Kalkan 9 years ago
parent
commit
d2b2d48888
  1. 127
      src/Volo.Abp/Volo/Abp/Domain/Entities/Entity.cs
  2. 29
      src/Volo.Abp/Volo/Abp/Domain/Entities/IEntity.cs
  3. 97
      src/Volo.Abp/Volo/Abp/Domain/Values/ValueObject.cs

127
src/Volo.Abp/Volo/Abp/Domain/Entities/Entity.cs

@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Volo.Abp.Domain.Entities
{
//TODO: Think on Entity class without PK
///// <summary>
///// A shortcut of <see cref="Entity{TPrimaryKey}"/> for most used primary key type (<see cref="int"/>).
///// </summary>
//public abstract class Entity : Entity<string>, IEntity<>
//{
//}
/// <summary>
/// Basic implementation of IEntity interface.
/// An entity can inherit this class of directly implement to IEntity interface.
/// </summary>
/// <typeparam name="TPrimaryKey">Type of the primary key of the entity</typeparam>
public abstract class Entity<TPrimaryKey> : IEntity<TPrimaryKey>
{
/// <summary>
/// Unique identifier for this entity.
/// </summary>
public virtual TPrimaryKey Id { get; set; }
/// <summary>
/// Checks if this entity is transient (it has not an Id).
/// </summary>
/// <returns>True, if this entity is transient</returns>
public virtual bool IsTransient()
{
if (EqualityComparer<TPrimaryKey>.Default.Equals(Id, default(TPrimaryKey)))
{
return true;
}
//Workaround for EF Core since it sets int/long to min value when attaching to dbcontext
if (typeof(TPrimaryKey) == typeof(int))
{
return Convert.ToInt32(Id) <= 0;
}
if (typeof(TPrimaryKey) == typeof(long))
{
return Convert.ToInt64(Id) <= 0;
}
return false;
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj == null || !(obj is Entity<TPrimaryKey>))
{
return false;
}
//Same instances must be considered as equal
if (ReferenceEquals(this, obj))
{
return true;
}
//Transient objects are not considered as equal
var other = (Entity<TPrimaryKey>)obj;
if (IsTransient() && other.IsTransient())
{
return false;
}
//Must have a IS-A relation of types or must be same type
var typeOfThis = GetType().GetTypeInfo();
var typeOfOther = other.GetType().GetTypeInfo();
if (!typeOfThis.IsAssignableFrom(typeOfOther) && !typeOfOther.IsAssignableFrom(typeOfThis))
{
return false;
}
//TODO: How to handle this?
//if (this is IMayHaveTenant && other is IMayHaveTenant &&
// this.As<IMayHaveTenant>().TenantId != other.As<IMayHaveTenant>().TenantId)
//{
// return false;
//}
//if (this is IMustHaveTenant && other is IMustHaveTenant &&
// this.As<IMustHaveTenant>().TenantId != other.As<IMustHaveTenant>().TenantId)
//{
// return false;
//}
return Id.Equals(other.Id);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return Id.GetHashCode();
}
/// <inheritdoc/>
public static bool operator ==(Entity<TPrimaryKey> left, Entity<TPrimaryKey> right)
{
if (Equals(left, null))
{
return Equals(right, null);
}
return left.Equals(right);
}
/// <inheritdoc/>
public static bool operator !=(Entity<TPrimaryKey> left, Entity<TPrimaryKey> right)
{
return !(left == right);
}
/// <inheritdoc/>
public override string ToString()
{
return $"[{GetType().Name} {Id}]";
}
}
}

29
src/Volo.Abp/Volo/Abp/Domain/Entities/IEntity.cs

@ -0,0 +1,29 @@
namespace Volo.Abp.Domain.Entities
{
//TODO: Think on Entity class without PK
///// <summary>
///// A shortcut of <see cref="IEntity{TPrimaryKey}"/> for most used primary key type (<see cref="int"/>).
///// </summary>
//public interface IEntity : IEntity<int>
//{
//}
/// <summary>
/// Defines interface for base entity type. All entities in the system must implement this interface.
/// </summary>
/// <typeparam name="TPrimaryKey">Type of the primary key of the entity</typeparam>
public interface IEntity<TPrimaryKey>
{
/// <summary>
/// Unique identifier for this entity.
/// </summary>
TPrimaryKey Id { get; set; }
/// <summary>
/// Checks if this entity is transient (not persisted to database and it has not an <see cref="Id"/>).
/// </summary>
/// <returns>True, if this entity is transient</returns>
bool IsTransient();
}
}

97
src/Volo.Abp/Volo/Abp/Domain/Values/ValueObject.cs

@ -0,0 +1,97 @@
using System;
using System.Linq;
using System.Reflection;
namespace Volo.Abp.Domain.Values
{
//Inspired from https://blogs.msdn.microsoft.com/cesardelatorre/2011/06/06/implementing-a-value-object-base-class-supertype-patternddd-patterns-related/
/// <summary>
/// Base class for value objects.
/// </summary>
/// <typeparam name="TValueObject">The type of the value object.</typeparam>
public abstract class ValueObject<TValueObject> : IEquatable<TValueObject>
where TValueObject : ValueObject<TValueObject>
{
public bool Equals(TValueObject other)
{
if ((object)other == null)
{
return false;
}
var publicProperties = GetType().GetTypeInfo().GetProperties();
if (!publicProperties.Any())
{
return true;
}
return publicProperties.All(property => Equals(property.GetValue(this, null), property.GetValue(other, null)));
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
var item = obj as ValueObject<TValueObject>;
return (object)item != null && Equals((TValueObject)item);
}
public override int GetHashCode()
{
const int index = 1;
const int initialHasCode = 31;
var publicProperties = GetType().GetTypeInfo().GetProperties();
if (!publicProperties.Any())
{
return initialHasCode;
}
var hashCode = initialHasCode;
var changeMultiplier = false;
foreach (var property in publicProperties)
{
var value = property.GetValue(this, null);
if (value == null)
{
//support {"a",null,null,"a"} != {null,"a","a",null}
hashCode = hashCode ^ (index * 13);
continue;
}
hashCode = hashCode * (changeMultiplier ? 59 : 114) + value.GetHashCode();
changeMultiplier = !changeMultiplier;
}
return hashCode;
}
public static bool operator ==(ValueObject<TValueObject> x, ValueObject<TValueObject> y)
{
if (ReferenceEquals(x, y))
{
return true;
}
if (((object)x == null) || ((object)y == null))
{
return false;
}
return x.Equals(y);
}
public static bool operator !=(ValueObject<TValueObject> x, ValueObject<TValueObject> y)
{
return !(x == y);
}
}
}
Loading…
Cancel
Save