基于DDD与Ardalis Clean架构,如何查询DocumentType列表?
解决方案
1. 在Document聚合根的仓储中新增查询方法
既然DocumentType属于Document聚合,直接在IDocumentRepository里加一个专门返回可用类型列表的方法,完全符合“仅为聚合根建仓储”的规则:
public interface IDocumentRepository : IRepository<Document> { Task<IEnumerable<DocumentType>> GetAllDocumentTypesAsync(CancellationToken cancellationToken = default); }
实现时可以直接查询数据库中所有不重复的DocumentType,如果是预定义类型也可以直接返回固定集合,灵活度很高。
2. 将DocumentType设计为值对象+静态/配置化列表
如果DocumentType是固定的业务分类(比如合同、发票、报告),把它做成值对象,同时在领域层维护一个可用类型的静态列表:
public record DocumentType(string Value) { // 预定义类型 public static readonly DocumentType Contract = new("Contract"); public static readonly DocumentType Invoice = new("Invoice"); public static readonly DocumentType Report = new("Report"); // 返回所有可用类型 public static IEnumerable<DocumentType> GetAll() => new[] { Contract, Invoice, Report }; }
前端直接调用DocumentType.GetAll()就能拿到列表,连数据库查询都省了。如果类型需要动态配置(比如从数据库加载),可以在领域层加个DocumentTypeProvider服务,依赖IDocumentRepository来获取数据。
3. 用领域服务封装类型查询逻辑
如果想保持仓储的单一职责,不想在仓储里加额外查询,可以创建一个DocumentTypeService领域服务,注入IDocumentRepository后封装查询逻辑:
public class DocumentTypeService { private readonly IDocumentRepository _documentRepository; public DocumentTypeService(IDocumentRepository documentRepository) { _documentRepository = documentRepository; } public async Task<IEnumerable<DocumentType>> GetAvailableTypesAsync(CancellationToken cancellationToken) { var allDocuments = await _documentRepository.ListAsync(cancellationToken); return allDocuments.Select(d => d.Type).Distinct(); } }
为什么不把DocumentType设为聚合根?
你的顾虑完全正确——DocumentType没有脱离Document的独立业务行为,单独做成聚合根会形成贫血模型,还会引入不必要的复杂度,违背DDD“聚合根封装完整业务边界”的核心原则。
内容的提问来源于stack exchange,提问作者Alexandru Tuca
相关产品推荐
相关产品推荐

