mirror of https://github.com/abpframework/abp.git
3 changed files with 253 additions and 0 deletions
@ -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}]"; |
|||
} |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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…
Reference in new issue