何时将DTO映射回其实体对应物是否合适

时间:2015-01-22 14:27:41

标签: domain-driven-design dto

从我阅读和实现的内容来看,DTO是从Data模型中保存值子集的对象,在大多数情况下,这些是不可变对象。

我需要传递新值还是更改回数据库的情况怎么样?

我应该直接使用我的演示层中的DAL中的数据模型/实际实体吗?

或者我应该创建一个可以从表示层传递到业​​务层然后将其转换为实体的DTO,然后通过ORM调用在DB中进行更新。这写的代码太多了吗?我假设如果表示层没有数据模型的概念,则需要这样做。如果我们采用这种方法,我应该在提交更改之前在BLL层再次获取对象吗?

3 个答案:

答案 0 :(得分:20)

一些想法:

  • DTO是一个加载的术语,但由于它代表Data Transfer 对象,我将其视为一个纯技术的,可能可序列化的container来从一个获取数据指向另一个,通常是跨层或可能是层。在处理业务问题的层中,例如DDD中的Domain层,这些流通的小数据结构往往被命名为Value Objects,因为它们具有商业意义并且是域的泛在语言的一部分。 DTO和Value Objects之间存在各种细微差别,例如您通常不需要比较DTO,而比较和相等是VO中的一个重要问题(如果封装数据相等,则两个VO相等)。 p>

  • DDD强调丰富领域模型的理念。这意味着您通常不会简单地将DTO的一对一映射到域实体,而是尝试将业务操作建模为实体中的意图揭示方法。例如,您不会使用setter修改User的{​​{1}},StreetCity,而是调用ZipCode方法,{{ 1}}是域层中声明的值对象。

  • DTO通常不会到达域层,而是通过应用层的过滤器。它可以是控制器或专用的应用程序服务。它的应用层对象知道如何将从客户端获得的DTO转换为对域层实体(通常是从存储库加载的聚合根)的正确调用。上面的另一个改进是构建tasked-based UIs,其中用户不发送以数据为中心的DTO,而是发送反映其最终目标的命令。

因此,将DTO映射到实体并不是DDD的做事方式,它更多地表示面向CRUD的方法。

答案 1 :(得分:3)

  

我应该直接使用我的演示层中的DAL中的数据模型/实际实体吗?

这适用于中小型项目。但是当你有一个超过5个开发人员的大型项目,其中不同的层被分配给不同的团队时,项目可以使用DTO将数据层与表示层分开。

在中间使用DTO时,表示层中的任何更改都不会影响数据层(反之亦然)

  

或者我应该创建一个可以从表示层传递到业​​务层然后将其转换为实体的DTO,然后通过ORM调用在DB中进行更新。这写的代码太多了吗?我假设如果表示层没有数据模型的概念,则需要这样做。如果我们采用这种方法,我应该在提交更改之前在BLL层再次获取对象吗?

对于创建新实体,那是通常的方法(例如“新用户”)。要更新现有实体,您不要将DTO转换为实体,而是获取现有实体,映射新值然后启动ORM更新。

UpdateUser(UserDto userDto)
{
    // Fetch
    User user = userRepository.GetById(userDto.ID);

    // Map
    user.FirstName = userDTO.FirstName;
    user.LastName = userDTO.LastName;

    // ORM Update
    userRepository.Update(user);
    userRepository.Commit();
}

对于拥有许多开发人员的大型项目,编写过多代码的缺点与其提供的解耦的巨大优势相比是最小的。

请参阅我关于Why use a DTO

的帖子

答案 2 :(得分:1)

我的观点是,DTO代表合同(或消息,如果你愿意),它们构成了聚合根与外部世界之间互动的基础。它们在域中定义,AR需要能够处理传入的实例并提供传出的实例。 (请注意,在大多数情况下,DTO实例将由AR提供或由AR处理,但不能同时处理两者,因为有一个双向流动的DTO通常违反关注点分离 。)

同时,AR负责提供业务逻辑,通过该逻辑处理DTO中包含的数据。表示层(或任何其他参与者,包括数据访问层,就此而言)可以自由地将它想要的任何乱码放入DTO并请求AR处理它,并且AR必须能够解释DTO的内容作为胡言乱语并提出例外。

由于此要求,简单地将DTO映射回其实体对应项是不合适的。

必须始终通过AR中的逻辑处理DTO,以便影响实体的变化,可能将其置于DTO描述的状态。