Domain driven design 何时将DTO映射回其实体对应项是合适的

Domain driven design 何时将DTO映射回其实体对应项是合适的,domain-driven-design,dto,Domain Driven Design,Dto,从我阅读和实现的内容来看,DTO是保存数据模型中的一个子集的对象,在大多数情况下,这些是不可变的对象 如果我需要将新值或更改传递回数据库,该怎么办 我是否应该在表示层中直接使用DAL中的数据模型/实际实体 或者我应该创建一个DTO,它可以从表示层传递到业务层,然后将其转换为实体,然后通过ORM调用在DB中更新。这是不是写了太多的代码?我假设,如果表示层没有数据模型的概念,就需要这样做。如果我们采用这种方法,我是否应该在提交更改之前在BLL层再次获取对象?我的观点是,DTO代表构成聚合根和外部世界

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

如果我需要将新值或更改传递回数据库,该怎么办

我是否应该在表示层中直接使用DAL中的数据模型/实际实体


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

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

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

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

DTO必须始终通过AR中的逻辑进行处理,以影响实体中的变化,从而使其达到DTO描述的状态

我是否应该在表示层中直接使用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();
}
对于有许多开发人员的大型项目,编写太多代码的缺点与它提供的解耦的巨大优势相比是最小的

请参阅我的帖子,了解一些想法:

  • DTO是一个已加载的术语,但由于它代表数据传输对象,我认为它更像是一个纯技术性的、潜在的可序列化的术语,用于将数据从一个点传输到另一个点,通常是跨层或可能跨层传输。在一个处理业务关注点的层中,例如DDD中的域层,这些循环的小数据结构往往被命名为值对象,因为它们具有业务意义,并且是域中普遍存在的语言的一部分。DTO和值对象之间存在各种细微的差异,例如通常不需要比较DTO,而比较和相等是VO中的一个重要问题(如果封装的数据相等,则两个VO相等)

  • DDD强调了丰富领域模型的思想。这意味着您通常不会简单地将DTO的一对一映射到域实体,而是尝试将业务操作建模为实体中的意图揭示方法。例如,您不会使用setter来修改
    用户
    街道
    城市
    ZipCode
    ,而是调用
    moveTo(Address newAddress)
    方法,
    地址
    作为域层中声明的值对象

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


因此,将DTO映射到实体并不是真正的DDD方式,它更像是一种面向CRUD的方法

我还想补充一点,如果您正在进行DDD/CQR,聚合根将永远不会提供DTO,因为它们将来自视图模型。但是,由于问题不是关于DDD/CQR,我假设您使用AR来获取表示层显示的数据。我同意您的粗体陈述,但不同意关于DTO接口的部分。DTO在定义上没有行为,接口的目的是提供行为契约,那么为什么要使用DTO接口呢?此外,域实体不接受来自客户端的原始DTO,大多数情况下,它首先通过应用程序层。应用层服务知道如何调用实体/AR方法,并将值传递给它们