You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于DDD与.NET的协议附件流程设计技术问询

协议系统的RESTful+DDD设计与技术疑问

我正在设计一个协议系统,每个协议可包含多个附件,希望以RESTful和DDD的方式实现。

领域模型代码

public class Agreement : AggregateRoot 
{
   public Guid Id { get; }
   public Salary Salary { get; private set; } //值对象
   public IReadOnlyCollection<Attachment> Attachments { get; } //实体
}

public class Attachment: Entity
{
   public Guid Id { get;  } //系统ID
   public string FileName { get; private set; } 
   public string ExternalId { get; } //指向OneDrive blob存储
}

业务流程

  • 通过独立端点POST /attachments上传附件,向UI客户端返回OneDrive最新附件ID(externalId);
  • 将每个附件ID(externalId)添加到POST /agreements请求体中,用于创建协议及关联附件。

方案优点

  • 协议端点仅接收JSON请求体,无需包含文件字节数组的多部分请求,更符合RESTful规范,降低客户端复杂度;
  • 提升性能,无需在单个主请求中上传多个文件,UI中每次点击文件上传都会在创建协议前触发文件上传。

方案缺点

  • 会产生孤儿附件,需实现定时CRON任务清理;
  • 创建操作不再原子化,协议流程分为两步。

技术问题解答

1. Attachment实体晚于文件本身上传创建是否可行?

完全可行。从DDD角度看,Attachment实体的核心职责是记录与协议关联的文件元数据(文件名、外部存储ID),而文件存储属于基础设施层操作。先通过/attachments端点完成文件上传拿到externalId,再基于这个ID创建Attachment实体并关联到协议,本质是把文件存储的基础设施操作和领域实体的创建逻辑解耦,反而更符合关注点分离原则。只要在创建Attachment时校验externalId对应的OneDrive文件存在,就不会有问题。

2. 清理定时任务触发时无法单独加载附件,采用CQRS模式能否引入仅针对附件的专用读模型?

当然可以。DDD中聚合根的边界限制只针对写操作——修改领域状态的操作必须通过聚合根保证业务规则一致性,但读操作不受此约束。CQRS的读模型本来就是为适配各种查询需求设计的,不需要遵循聚合边界。

你可以单独构建AttachmentReadModel,包含Id、ExternalId、AgreementId(关联协议ID,未关联则为null)、CreatedTime等字段,专门用于定时任务查询:扫描所有AgreementId为null且超过阈值时间的读模型记录,清理对应的OneDrive文件并删除读模型数据。这种方式既不违反DDD写端的聚合规则,又高效解决了孤儿附件的查询和清理问题。


内容的提问来源于stack exchange,提问作者Andrius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 03:55:24