ABP 如何写一个实体
例子:
聚合根:
public class Issue : FullAuditedAggregateRoot<Guid> //使用Guid作为键/标识符
{
public virtual string Title { get; private set; } //使用 SetTitle() 方法set
public virtual string Text { get; set; } //可以直接set,null值也是允许的
public virtual Guid? MilestoneId { get; set; } //引用其他聚合根
public virtual bool IsClosed { get; private set; }
public virtual IssueCloseReason? CloseReason { get; private set; } //一个枚举类型
public virtual Collection<IssueLabel> Labels { get; protected set; } //子集合
protected Issue()
{
/* 此构造函数是提供给ORM用来从数据库中获取实体.
* - 无需初始化Labels集合
因为它会被来自数据库的值覆盖.
- It's protected since proxying and deserialization tools
可能不适用于私有构造函数.
*/
}
//主构造函数
public Issue(
Guid id, //从调用代码中获取Guid值
[NotNull] string title, //表示标题不能为空.
string text = null,
Guid? milestoneId = null) //可选参数
{
Id = id;
Title = Check.NotNullOrWhiteSpace(title, nameof(title)); //验证
Text = text;
MilestoneId = milestoneId;
Labels = new Collection<IssueLabel>(); //总是初始化子集合
}
public virtual void SetTitle([NotNull] string title)
{
Title = Check.NotNullOrWhiteSpace(title, nameof(title)); //验证
}
/* AddLabel和RemoveLabel方法管理Labels集合
* 安全的方式(防止两次添加相同的标签) */
public virtual void AddLabel(Guid labelId)
{
if (Labels.Any(l => l.LabelId == labelId))
{
return;
}
Labels.Add(new IssueLabel(Id, labelId));
}
public virtual void RemoveLabel(Guid labelId)
{
Labels.RemoveAll(l => l.LabelId == labelId);
}
/* Close和ReOpen方法可保护一致性
* IsClosed 与 CloseReason 属性. */
public virtual void Close(IssueCloseReason reason)
{
IsClosed = true;
CloseReason = reason;
}
public virtual void ReOpen()
{
IsClosed = false;
CloseReason = null;
}
}
实体:
public class IssueLabel : Entity
{
public virtual Guid IssueId { get; private set; }
public virtual Guid LabelId { get; private set; }
protected IssueLabel()
{
}
public IssueLabel(Guid issueId, Guid labelId)
{
IssueId = issueId;
LabelId = labelId;
}
}
约定
哪里定义
- 务必在Domain层定义实体
如何定构造函数
- 务必定义一个 主构造函数 确保实体在创建时验证有效性, 在代码中通过主构造函数创建实体的新实例.
- 根据需求把主构造函数定义为 public,internal 或 protected internal . 如果它不是public的, 那么应该由领域服务来创建实体.
- 总是在主构造函数中初始化子集合.
- 千万不要在构造函数里生成Guid,Guid应该由调用方通过IGuidGenerator 生成
- 总是定义 protected 无参构造函数与ORM兼容.
与其他聚合根的关系
- 总是通过 id 引用 其他聚合根, 不要将导航属性添加到其他聚合根中.
实体的属性和方法
- 总是将属性与方法定义为 virtual (除了私有方法 ). 因为有些ORM和动态代理工具需要.
- 属的Setter 使用 private,protected,internal或protected internal 定义 , 保护实体的一致性和有效性
- 如果方法里要修改属性值,并持久化到数据库中,则方法必须用virtual修饰。
聚合根 主键:
- 总是使用 Id 属性做为聚合根主键
- 不要在聚合根中使用 复合主键.
- 所有的聚合根都使用 Guid 类型 主键
基类:
- 一定要继承 AggregateRoot
或根据需求继承下面的审计类 (CreationAuditedAggregateRoot , AuditedAggregateRoot 或 FullAuditedAggregateRoot ).
聚合边界
- 聚合尽可能小. 大多数聚合只有原始属性, 不会有子集合. 设计时就应考虑到。
- 较大的聚合会消耗更多的CPU和内存.

浙公网安备 33010602011771号