Entity.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using Abp.Extensions;
  5. namespace Abp.Domain.Entities
  6. {
  7. /// <summary>
  8. /// A shortcut of <see cref="Entity{TPrimaryKey}"/> for most used primary key type (<see cref="int"/>).
  9. /// </summary>
  10. [Serializable]
  11. public abstract class Entity : Entity<int>, IEntity
  12. {
  13. }
  14. /// <summary>
  15. /// Basic implementation of IEntity interface.
  16. /// An entity can inherit this class of directly implement to IEntity interface.
  17. /// </summary>
  18. /// <typeparam name="TPrimaryKey">Type of the primary key of the entity</typeparam>
  19. [Serializable]
  20. public abstract class Entity<TPrimaryKey> : IEntity<TPrimaryKey>
  21. {
  22. /// <summary>
  23. /// Unique identifier for this entity.
  24. /// </summary>
  25. public virtual TPrimaryKey Id { get; set; }
  26. /// <summary>
  27. /// Checks if this entity is transient (it has not an Id).
  28. /// </summary>
  29. /// <returns>True, if this entity is transient</returns>
  30. public virtual bool IsTransient()
  31. {
  32. if (EqualityComparer<TPrimaryKey>.Default.Equals(Id, default(TPrimaryKey)))
  33. {
  34. return true;
  35. }
  36. //Workaround for EF Core since it sets int/long to min value when attaching to dbcontext
  37. if (typeof(TPrimaryKey) == typeof(int))
  38. {
  39. return Convert.ToInt32(Id) <= 0;
  40. }
  41. if (typeof(TPrimaryKey) == typeof(long))
  42. {
  43. return Convert.ToInt64(Id) <= 0;
  44. }
  45. return false;
  46. }
  47. /// <inheritdoc/>
  48. public override bool Equals(object obj)
  49. {
  50. if (obj == null || !(obj is Entity<TPrimaryKey>))
  51. {
  52. return false;
  53. }
  54. //Same instances must be considered as equal
  55. if (ReferenceEquals(this, obj))
  56. {
  57. return true;
  58. }
  59. //Transient objects are not considered as equal
  60. var other = (Entity<TPrimaryKey>)obj;
  61. if (IsTransient() && other.IsTransient())
  62. {
  63. return false;
  64. }
  65. //Must have a IS-A relation of types or must be same type
  66. var typeOfThis = GetType();
  67. var typeOfOther = other.GetType();
  68. if (!typeOfThis.GetTypeInfo().IsAssignableFrom(typeOfOther) && !typeOfOther.GetTypeInfo().IsAssignableFrom(typeOfThis))
  69. {
  70. return false;
  71. }
  72. if (this is IMayHaveTenant && other is IMayHaveTenant &&
  73. this.As<IMayHaveTenant>().TenantId != other.As<IMayHaveTenant>().TenantId)
  74. {
  75. return false;
  76. }
  77. if (this is IMustHaveTenant && other is IMustHaveTenant &&
  78. this.As<IMustHaveTenant>().TenantId != other.As<IMustHaveTenant>().TenantId)
  79. {
  80. return false;
  81. }
  82. return Id.Equals(other.Id);
  83. }
  84. /// <inheritdoc/>
  85. public override int GetHashCode()
  86. {
  87. if (Id == null)
  88. {
  89. return 0;
  90. }
  91. return Id.GetHashCode();
  92. }
  93. /// <inheritdoc/>
  94. public static bool operator ==(Entity<TPrimaryKey> left, Entity<TPrimaryKey> right)
  95. {
  96. if (Equals(left, null))
  97. {
  98. return Equals(right, null);
  99. }
  100. return left.Equals(right);
  101. }
  102. /// <inheritdoc/>
  103. public static bool operator !=(Entity<TPrimaryKey> left, Entity<TPrimaryKey> right)
  104. {
  105. return !(left == right);
  106. }
  107. /// <inheritdoc/>
  108. public override string ToString()
  109. {
  110. return $"[{GetType().Name} {Id}]";
  111. }
  112. }
  113. }