为了我自己的清晰/自我教育,我正在尝试使用TDD DDD实现一个简单的订单输入应用程序。我的主要目标是通过分离问题来保持架构的清洁。
我有四层(现在)…
一个CustomerRepository类的持久性/ DAL可以执行GetById,Save,“聚合根”,客户及其相关订单和OrderItems的操作。为了允许“穷人的依赖注入”
>包含“业务实体”类的域/ BLL层,执行细粒度操作以帮助创建新订单,根据订单大小和客户位置应用税收,折扣,运输逻辑。
>应用程序Facade(应用程序服务/编排)包含大块,粗糙的类来编排“业务实体”,并减少与演示文稿(以及潜在的WebServices层)的喋喋不休。
>演示层
此外,我想在关键层之间传递POCO DTO,特别是在Persistence => Domain层和ApplicationFacade => Presentation层之间。所以,我有一个CustomerDto,OrderDto,OrderItemDto与共享包中定义的适当的关系。
我想使用构造函数注入向客户“业务实体”类注入一个ICustomerRepository的实现,然后调用“业务实体”上的Customer.Save()来启动创建/更新过程,最后调用Save方法CustomerRepository。毕竟,客户是“聚合根”,并具有保存所需的所有信息…它也是注入的CustomerRepository的“守护者”。
问题:
这是我打的一个障碍。我希望尽可能保持域/ BLL层的尽可能纯净,并避免将其与任何第三方框架和API相连,但是Customer.Save()方法需要将客户“聚合根”及其所有订单和订单项转换为他们的DTO版本用于传输到注入的Persistence层CustomerRepository …,这是Automapper的工作。
问题是…如果我不将Automapper放在Domain / BLL层中,我不太确定它应该去哪里。
即使它的作业是编排,它也不适合将它放在ApplicationFacade中。
因为我想保持原始状态,所以把它放在Domain / BLL层中绝对不是很正确。
因此,我觉得我错过了一些东西,我正在接近这一点,对工作部分应该如何共同完成这项任务的根本误解。有什么建议么? (请温柔,我是新来的,而且是新的,让我知道,如果我需要显示我迄今为止的一些代码。)
接下来,当实现存储库时,通常不需要在底层持久性技术和域类之间进行显式的DTO。使用诸如NHibernate和EF之类的ORM,域类和关系表之间的映射用映射类或基于XML的配置表示。因此,您的域类被隐式映射 – 不需要DTO。有些情况确实要求DTO,在这种情况下,DTO和域类之间的映射应该由存储库实现封装。这是您可以调用AutoMapper的地方。
最后,通常的做法是在表示层和应用/域层之间与DTO通信。要准确确定映射的位置,您必须深入了解最适合您的项目的体系结构。大多数现代DDD架构基于Hexagonal architecture.在六边形架构中,您的域位于中心,所有其他“层”将域调整到特定技术。例如,存储库可以被视为域和特定数据库技术之间的adapter。 ASP.NET WebAPI可以被看作是域和HTTP / REST之间的适配器。同样,表示层可以被看作是域和特定的适配器。 DTO可以在每个适配器中显示,适配器有责任与这些DTO进行映射。
一个典型的例子是使用应用程序服务在您的域上建立一个立面。没有DTO玩。接下来,使用ASP.NET WebAPI(一个适配器)创建一个服务层(在DDD中打开主机服务)。您创建ASP.NET WebAPI特定的DTO,由该适配器来映射到这些DTO。因此,如果您使用AutoMapper,则应在此层中调用它。这可以通过动作过滤器明确地或以aspect-oriented的方式完成。同样适用于表示层。表示层可以直接耦合到应用程序服务,也可以连接到ASP.NET WebAPI开放主机服务。在这两种情况下,表示层都有责任在域类(来自WebAPI的应用程序服务或DTO)和其自己的基元(如viewmodel)之间进行映射。