基于Clean Architecture的C#销售系统项目循环引用问题求解
解决Clean Architecture中的循环引用问题
你的核心问题是违反了Clean Architecture的依赖规则——把仓储抽象接口放在了外层(Sales.Adapters),导致核心层(Sales.Business)不得不依赖外层,同时外层又依赖核心层的领域实体,形成循环引用。下面是具体的解决方案:
正确的架构调整方案
根据Clean Architecture的依赖倒置原则,业务所需的抽象接口属于核心层的一部分,而非外层适配器。你需要把仓储接口移到Sales.Business层,彻底理顺依赖方向:
1. 迁移仓储接口到核心层
将IOrderRepository从Sales.Adapters移至Sales.Business,比如放在Sales.Business.Ports或Sales.Business.Repositories命名空间下:
namespace Sales.Business.Ports; // 接口属于核心层,直接引用领域实体Order public interface IOrderRepository { int SaveOrder(Order order); // 其他业务所需的仓储方法 }
2. 调整各层依赖关系
- Sales.Business(核心层):不再依赖任何外层包,内部包含领域实体、用例和对外抽象接口。
- Sales.Adapters:依赖Sales.Business,控制器可以通过构造函数注入
IOrderRepository,调用用例或直接操作抽象接口。 - Sales.Infrastructure:依赖Sales.Business,实现
IOrderRepository接口,负责将领域实体转换为数据库模型并执行持久化逻辑:
namespace Sales.Infrastructure.Repositories; public class SqlOrderRepository : IOrderRepository { public int SaveOrder(Order order) { // 这里将领域实体Order转换为EF Core实体或直接操作数据库 // 实现具体的保存逻辑 return 1; // 返回订单ID示例 } }
3. 用例层的实现
StartOrder用例在核心层内部依赖IOrderRepository,通过构造函数注入,完全符合依赖规则:
namespace Sales.Business.UseCases; public class StartOrderUseCase { private readonly IOrderRepository _orderRepository; public StartOrderUseCase(IOrderRepository orderRepository) { _orderRepository = orderRepository; } public int Execute() { var order = new Order(); // 执行核心业务规则,初始化订单 return _orderRepository.SaveOrder(order); } }
为什么之前的方案不行?
- 把仓储接口放在Sales.Adapters,本质是让核心层依赖外层,违反了Clean Architecture“外层依赖核心层,核心层不依赖任何外层”的核心规则。
- 用OrderDTO绕路是不必要的,仓储接口属于业务抽象,直接使用领域实体是合理的,持久化时的模型转换应该放在基础设施层的实现里,而非抽象接口层。
调整后的依赖关系:Sales.Infrastructure → Sales.BusinessSales.Adapters → Sales.BusinessSales.Business 无对外依赖
完全消除了循环引用,同时严格遵循Clean Architecture的设计原则。
内容的提问来源于stack exchange,提问作者AlexQL
相关产品推荐
相关产品推荐

