我正在(重新)设计大型应用程序,我们使用基于DDD的多层架构。

我们有带有数据层(存储库的实现)、领域层(域模型和接口的定义——存储库、服务、工作单元)、服务层(服务的实现)的MVC。到目前为止,我们在所有层上使用域模型(主要是实体),并且仅将dto用作视图模型(在控制器中,服务返回域模型,控制器创建视图模型,并将其传递给视图)。

I'v read countless articles about using, not using, mapping and passing DTOs. I understand that there's no any definitive answer, but I'm not sure if it's ok or not returning domain models from services to controllers. If I return domain model, it's still never passed to the view, since controller always creates view-specific view model - in this case, it seem legit. On the other hand, it doesn't feel right when domain model leaves business layer (service layer). Sometimes service needs to return data object that wasn't defined in the domain and then we either have to add new object to the domain that isn't mapped, or create POCO object (this is ugly, since some services return domain models, some effectively return DTOs).

The question is - if we strictly use view models, is it ok to return domain models all the way to controllers, or should we always use DTOs for communication with service layer? If so, is it ok to adjust domain models based on what services need? (Frankly I don't think so, since services should consume what domain has.) If we should strictly stick to DTOs, should they be defined in service layer? (I think so.) Sometimes it's clear that we should use DTOs (e.g., when service performs lot of business logic and creates new objects), sometimes it's clear that we should use just domain models (e.g., when Membership service returns anemic User(s) - it seems it wouldn't make much sense to create DTO that is the same as domain model) - but I prefer consistency and good practices.

文章域vs DTO vs ViewModel -如何以及何时使用它们?(以及其他一些文章)与我的问题非常相似,但它没有回答这个问题。我应该用EF在存储库模式中实现dto吗?也类似,但它不处理DDD。

免责声明:我不打算仅仅因为任何设计模式的存在而使用它,另一方面,我想使用好的设计模式和实践,因为它有助于设计应用程序作为一个整体,有助于分离关注点,即使使用特定的模式不是“必要的”,至少目前是这样。


当前回答

我建议分析这两个问题:

Are your upper layers (i.e. view & view models / controllers) consuming the data in a different way of what the domain layer exposes? If there is a lot of mapping being done or even logic involved I'll suggest revisiting your design: it should probably be closer to how the data is actually used. How likely is it that you deeply change your upper layers? (e.g. swapping ASP.NET for WPF). If this is highly unlike and your architecture is not very complex, you may be better off exposing as many domain entities as you can.

恐怕这是一个相当广泛的话题,它实际上涉及到您的系统有多复杂及其需求。

其他回答

It seems that your application is big and complex enough as you have decided to go through DDD approach. Don't return your poco entities or so called domain entities and value objects in you service layer. If you want to do this then delete your service layer because you don't need it anymore! View Model or Data transfer objects should live in Service layer because they should map to domain model members and vice versa. So why do you need to have DTO? In complex application with lots of scenarios you should separate the concerns of domain and you presentation views, a domain model could be divided into several DTO and also several Domain models could be collapsed into a DTO. So it's better to create your DTO in layered architecture even it would be the same as your model.

我们应该总是使用dto与服务层通信吗? 是的,你必须通过你的服务层返回DTO,因为你必须在服务层中通过域模型成员与存储库对话,并将它们映射到DTO并返回到MVC控制器,反之亦然。

是否可以根据服务需求调整域模型? 服务只与存储库、域方法和域服务对话,您应该根据自己的需求解决域内的业务,而不是告诉域需要什么。

如果我们应该严格遵循dto,那么它们应该在服务层定义吗?是的,尝试稍后在服务中使用DTO或ViewModel,因为它们应该映射到服务层中的域成员,并且在应用程序的控制器中放置DTO不是一个好主意(尝试在服务层中使用请求响应模式),干杯!

我建议分析这两个问题:

Are your upper layers (i.e. view & view models / controllers) consuming the data in a different way of what the domain layer exposes? If there is a lot of mapping being done or even logic involved I'll suggest revisiting your design: it should probably be closer to how the data is actually used. How likely is it that you deeply change your upper layers? (e.g. swapping ASP.NET for WPF). If this is highly unlike and your architecture is not very complex, you may be better off exposing as many domain entities as you can.

恐怕这是一个相当广泛的话题,它实际上涉及到您的系统有多复杂及其需求。

Late to the party, but I’m facing the exact same type of architecture and I’m leaning towards “only DTOs from service”. This is mainly because I’ve decided to only use domain objects/aggregates to maintain validity within the object, thus only when updating, creating or deleting. When we’re querying for data, we only use EF as a repository and maps the result to DTOs. This makes us free to optimize read queries and not adapt them to business objects, often using database functions as they are fast.

每个服务方法都定义了自己的契约,因此随着时间的推移更容易维护。我希望。

根据我的经验,你应该做些实际的事情。“最好的设计是最简单的设计”——爱因斯坦。有了这样的思想……

如果我们严格使用视图模型,是否可以将域模型一直返回到控制器,或者我们应该始终使用dto与服务层通信?

当然没关系!如果你有域实体,DTO和视图模型,那么包括数据库表,你在应用程序中重复的所有字段在4个地方。我曾参与过一些大型项目,其中领域实体和视图模型工作得很好。唯一的例外是,如果应用程序是分布式的,而服务层位于另一台服务器上,在这种情况下,由于序列化的原因,需要通过网络发送dto。

如果是,是否可以根据服务需求调整域模型?(坦白地说,我不这么认为,因为服务应该消费域拥有的东西。)

一般来说,我同意并说不,因为域模型通常是业务逻辑的反映,通常不是由该逻辑的消费者塑造的。

如果我们应该严格遵循dto,那么它们应该在服务层定义吗?(我想是的。)

如果你决定使用它们,我同意并说是的,服务层是一个完美的地方,因为它在一天结束时返回dto。

好运!

我来晚了,但这是一个如此常见而重要的问题,我觉得有必要做出回应。

你所说的“服务”是指Evan在蓝皮书中描述的“应用层”吗?我假设您知道,在这种情况下,答案是它们不应该返回dto。我建议阅读蓝皮书的第4章,标题为“隔离领域”。

在这一章中,Evans阐述了以下关于层次的内容:

把一个复杂的程序划分成几层。在每一层中开发一个内聚的设计,它只依赖于下面的层。

这是有充分理由的。如果您使用部分顺序的概念作为软件复杂性的度量,那么让一层依赖于它上面的一层会增加复杂性,从而降低可维护性。

将此应用于您的问题,dto实际上是用户界面/表示层所关注的适配器。请记住,远程/跨进程通信正是DTO的目的(值得注意的是,Fowler在那篇文章中也反对将DTO作为服务层的一部分,尽管他不一定是在谈论DDD语言)。

如果应用程序层依赖于这些dto,那么它就依赖于它上面的一层,复杂性就会增加。我可以保证这会增加维护软件的难度。

例如,如果您的系统与其他几个系统或客户端类型进行接口,每个系统或客户端类型都需要自己的DTO,该怎么办?如何知道应用程序服务的方法应该返回哪个DTO ?如果您所选择的语言不允许基于返回类型重载方法(在本例中是服务方法),您将如何解决这个问题呢?而且,即使您找到了一种方法,为什么要违背应用层来支持表示层关注点呢?

在实践中,这是朝着意大利面条式架构的方向迈进的一步。我亲身经历过这种权力下放及其结果。

在我目前工作的地方,应用程序层中的服务返回域对象。我们不认为这是一个问题,因为界面(即UI/表示)层依赖于域层,它在它下面。此外,这种依赖被最小化为“仅引用”类型的依赖,因为:

a)接口层只能将这些域对象作为调用应用层获得的只读返回值访问

b)应用层服务上的方法只接受该层定义的“原始”输入(数据值)或对象参数(必要时减少参数计数)。具体来说,应用程序服务从不接受域对象作为输入。

接口层使用在接口层本身定义的映射技术从域对象映射到dto。这再次使dto集中于由接口层控制的适配器。