何处在DDD +分层架构中实现Automapper

时间:2012-12-07 22:41:53

标签: architecture domain-driven-design automapper layer

背景: 为了我自己的清晰度/自我教育,我试图使用TDD + DDD实现一个简单的订单输入应用程序。我的主要目标是通过分离问题来保持架构的清洁。

我有四层(现在)......

  1. 具有CustomerRepository类的Persistence / DAL,可以对“聚合根”,客户及其相关订单和OrderItem执行GetById,Save,操作。为了允许“穷人的依赖注射”

  2. 包含“业务实体”类的域/ BLL层,这些类执行细粒度操作以帮助创建新订单,根据订单大小和客户位置应用税,折扣,装运逻辑。

  3. 应用程序Facade(App services / orchestration)包含大块,粗粒度的类来编排“业务实体”并减少与演示文稿(以及可能是WebServices层)的聊天。

  4. 表示层

  5. 此外,我想在关键层之间传递POCO DTO ...特别是在Persistence => Domain层和ApplicationFacade => Presentation层之间。所以,我有CustomerDto,OrderDto,OrderItemDto以及在共享包中定义的适当关系。

    我想使用Constructor Injection将ICustomerRepository的实现注入到Customer“业务实体”类中,然后在“业务实体”上调用Customer.Save()以启动创建/更新过程,最终调用在CustomerRepository上保存方法。毕竟,客户是“聚合根”并拥有保存所需的所有信息......它也是注入的CustomerRepository的“守护者”。

    问题: 这是我遇到麻烦的地方。我希望尽可能保持Domain / BLL Layer的纯度,并避免将其与任何第三方框架和API相结合, Customer.Save()方法需要翻译Customer“聚合根”及其所有Orders和OrderItem到他们的DTO版本中,以便传输到注入的持久层CustomerRepository ......这是Automapper的工作。

    问题是......如果我没有将Automapper放在Domain / BLL层中,我不确定哪里它应该去。

    将它放在ApplicationFacade中感觉不对,即使它的工作是编排。

    将它放在Domain / BLL层中肯定是不对的,因为我想让它保持原始状态。

    因此,我觉得我错过了一些东西......我正在接近这个问题时,对工作部分应该如何共同完成这项任务的基本误解。有什么建议? (请保持温和,我对这一切都是新手,对SO来说是新手。如果我需要展示一些我到目前为止的代码,请告诉我。)

1 个答案:

答案 0 :(得分:47)

为了回答您的具体问题,我将更全面地介绍您的架构。您为项目设计的体系结构与DDD使用的典型体系结构略有不同。虽然您分配职责的方式很典型,但在DDD中,域类不对其自身的持久性负责。事实上,DDD的口号是persistence ignorance。这基本上意味着域类是持久性无知的 - 它们没有Save方法。相反,应用程序服务(架构中的应用程序外观层)与存储库协调以重构和持久化域实体。

接下来,在实现存储库时,通常不需要在底层持久性技术和域类之间使用显式DTO。对于诸如NHibernate和EF之类的ORM,域类和关系表之间的映射用映射类或基于XML的配置表示。因此,您的域类是隐式映射的 - 不需要DTO。有些情况下会调用DTO,在这种情况下,DTO和域类之间的映射应该由存储库实现封装。这是您可以调用AutoMapper的地方。

最后,通常使用DTO在表示层和应用程序/域层之间进行通信。要确定映射的确切位置,您必须深入挖掘最适合您项目的体系结构。大多数现代DDD架构都基于Hexagonal architecture。在六边形体系结构中,您的域位于中心,所有其他“层”使域适应特定技术。例如,存储库可以被视为域与特定数据库技术之间的adapter。 ASP.NET WebAPI可以看作域和HTTP / REST之间的适配器。同样,表示层可以看作域和特定域之间的适配器。 DTO可以在每个适配器中显示,并且适配器负责映射到这些DTO以及从这些DTO映射。

一个典型的例子是使用应用程序服务在您的域上建立一个外观。没有DTO在玩。接下来,使用ASP.NET WebAPI(适配器)创建服务层(DDD中的开放主机服务)。您可以创建ASP.NET WebAPI特定的DTO,这个适配器可以映射到这些DTO以及从这些DTO映射。因此,如果您使用AutoMapper,则应在此图层中调用它。这可以通过动作过滤器明确地或以aspect-oriented方式完成。表示层也是如此。表示层可以直接耦合到应用程序服务,也可以耦合到ASP.NET WebAPI开放主机服务。在任何一种情况下,表示层都有责任在域类(来自应用程序服务或来自WebAPI的DTO)与其自己的基元(如ViewModel)之间进行映射。