文章目錄
- 實體
- Product實體
- Entity類
- 聚合根
- 官方架構已經給出了幾種聚合根,擴充了不同的常用字段
- 額外屬性
實體
實體是DDD(Domain Driven Design)中核心概念.Eric Evans是這樣描述實體的 “一個沒有從其屬性,而是通過連續性和身份的線索來定義的對象”
實體通常映射到關系型資料庫的表中。1
Product實體
按照項目結構,Product應該建立在Domain項目中,是以源碼是這樣的
目錄結構

代碼
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Domain.Entities;
namespace LY.Shop.Models
{
public class Product :Entity<Guid> // AggregateRoot<Guid>
{
public string ProductName { get; set; }
public string ProductUnit { get; set; }
public string ProductDescription { get; set; }
public decimal ProductPrice { get; set; }
public decimal StoreNumbers { get; set; }
public string Note { get; set; }
protected Product()
{
}
public Product(Guid id)
: base(id)
{
}
}
}
Entity類
這個類是abp架構提供的,看一下他的源碼
using System;
using System.Collections.Generic;
using System.Reflection;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Domain.Entities
{
/// <inheritdoc/>
[Serializable]
public abstract class Entity : IEntity
{
/// <inheritdoc/>
public override string ToString()
{
return $"[ENTITY: {GetType().Name}] Keys = {GetKeys().JoinAsString(", ")}";
}
public abstract object[] GetKeys();
}
/// <inheritdoc cref="IEntity{TKey}" />
[Serializable]
public abstract class Entity<TKey> : Entity, IEntity<TKey>
{
/// <inheritdoc/>
public virtual TKey Id { get; protected set; }
protected Entity()
{
}
protected Entity(TKey id)
{
Id = id;
}
public bool EntityEquals(object obj)
{
if (obj == null || !(obj is Entity<TKey>))
{
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<TKey>)obj;
if (EntityHelper.HasDefaultId(this) && EntityHelper.HasDefaultId(other))
{
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;
}
//Different tenants may have an entity with same Id.
if (this is IMultiTenant && other is IMultiTenant &&
this.As<IMultiTenant>().TenantId != other.As<IMultiTenant>().TenantId)
{
return false;
}
return Id.Equals(other.Id);
}
public override object[] GetKeys()
{
return new object[] {Id};
}
/// <inheritdoc/>
public override string ToString()
{
return $"[ENTITY: {GetType().Name}] Id = {Id}";
}
}
}
這份源碼沒有什麼好分析的,就是做了一個基類,重寫了幾個常用的方法。
聚合根
“聚合是域驅動設計中的一種模式.DDD的聚合是一組可以作為一個單元處理的域對象.例如,訂單及訂單系列的商品,這些是獨立的對象,但将訂單(連同訂單系列的商品)視為一個聚合通常是很有用的”2
源碼
namespace Volo.Abp.Domain.Entities
{
/// <summary>
/// Defines an aggregate root. It's primary key may not be "Id" or it may have a composite primary key.
/// Use <see cref="IAggregateRoot{TKey}"/> where possible for better integration to repositories and other structures in the framework.
/// </summary>
public interface IAggregateRoot : IEntity
{
}
/// <summary>
/// Defines an aggregate root with a single primary key with "Id" property.
/// </summary>
/// <typeparam name="TKey">Type of the primary key of the entity</typeparam>
public interface IAggregateRoot<TKey> : IEntity<TKey>, IAggregateRoot
{
}
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
namespace Volo.Abp.Domain.Entities
{
[Serializable]
public abstract class AggregateRoot : Entity,
IAggregateRoot,
IGeneratesDomainEvents,
IHasExtraProperties,
IHasConcurrencyStamp
{
public virtual Dictionary<string, object> ExtraProperties { get; protected set; }
[DisableAuditing]
public virtual string ConcurrencyStamp { get; set; }
private readonly ICollection<object> _localEvents = new Collection<object>();
private readonly ICollection<object> _distributedEvents = new Collection<object>();
protected AggregateRoot()
{
ExtraProperties = new Dictionary<string, object>();
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
protected virtual void AddLocalEvent(object eventData)
{
_localEvents.Add(eventData);
}
protected virtual void AddDistributedEvent(object eventData)
{
_distributedEvents.Add(eventData);
}
public virtual IEnumerable<object> GetLocalEvents()
{
return _localEvents;
}
public virtual IEnumerable<object> GetDistributedEvents()
{
return _distributedEvents;
}
public virtual void ClearLocalEvents()
{
_localEvents.Clear();
}
public virtual void ClearDistributedEvents()
{
_distributedEvents.Clear();
}
}
[Serializable]
public abstract class AggregateRoot<TKey> : Entity<TKey>,
IAggregateRoot<TKey>,
IGeneratesDomainEvents,
IHasExtraProperties,
IHasConcurrencyStamp
{
public virtual Dictionary<string, object> ExtraProperties { get; protected set; }
[DisableAuditing]
public virtual string ConcurrencyStamp { get; set; }
private readonly ICollection<object> _localEvents = new Collection<object>();
private readonly ICollection<object> _distributedEvents = new Collection<object>();
protected AggregateRoot()
{
ExtraProperties = new Dictionary<string, object>();
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
protected AggregateRoot(TKey id)
: base(id)
{
ExtraProperties = new Dictionary<string, object>();
ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
protected virtual void AddLocalEvent(object eventData)
{
_localEvents.Add(eventData);
}
protected virtual void AddDistributedEvent(object eventData)
{
_distributedEvents.Add(eventData);
}
public virtual IEnumerable<object> GetLocalEvents()
{
return _localEvents;
}
public virtual IEnumerable<object> GetDistributedEvents()
{
return _distributedEvents;
}
public virtual void ClearLocalEvents()
{
_localEvents.Clear();
}
public virtual void ClearDistributedEvents()
{
_distributedEvents.Clear();
}
}
}
聚合根中除了繼承IEntity接口外,還繼承了其他幾個接口(稍後再說),主要思想還是對IEntity再一次封裝。
官方架構已經給出了幾種聚合根,擴充了不同的常用字段
- CreationAuditedEntity 和 CreationAuditedAggregateRoot 實作了 ICreationAuditedObject 接口.
- AuditedEntity 和 AuditedAggregateRoot 實作了 IAuditedObject 接口.
- FullAuditedEntity and FullAuditedAggregateRoot 實作了 IFullAuditedObject 接口.
額外屬性
關于額外屬性使用到的情況非常少,大緻就是通過json存在資料庫中,映射到實體的
ExtraProperties
屬性,通過GetProperty 和 SetProperty方法進行取值和寫值,可以通過HasProperty 判斷是否存在該屬性,也可以通過RemoveProperty 方法删除擴充屬性中的某一個屬性。
- 官網原話,值得推敲,Eric Evans的原話咱沒看懂,但是 下面語句映射到關系資料庫表中就清晰了許多。 ↩︎
- 聚合根其實就是對實體的進一步封裝。繼承自IEntity接口 ↩︎