从我阅读和实现的内容来看,DTO是从Data模型中保存值子集的对象,在大多数情况下,这些是不可变对象。
我需要传递新值还是更改回数据库的情况怎么样?
我应该直接使用我的演示层中的DAL中的数据模型/实际实体吗?
或者我应该创建一个可以从表示层传递到业务层然后将其转换为实体的DTO,然后通过ORM调用在DB中进行更新。这写的代码太多了吗?我假设如果表示层没有数据模型的概念,则需要这样做。如果我们采用这种方法,我应该在提交更改之前在BLL层再次获取对象吗?
答案 0 :(得分:20)
一些想法:
DTO是一个加载的术语,但由于它代表Data Transfer 对象,我将其视为一个纯技术的,可能可序列化的container来从一个获取数据指向另一个,通常是跨层或可能是层。在处理业务问题的层中,例如DDD中的Domain层,这些流通的小数据结构往往被命名为Value Objects,因为它们具有商业意义并且是域的泛在语言的一部分。 DTO和Value Objects之间存在各种细微差别,例如您通常不需要比较DTO,而比较和相等是VO中的一个重要问题(如果封装数据相等,则两个VO相等)。 p>
DDD强调丰富领域模型的理念。这意味着您通常不会简单地将DTO的一对一映射到域实体,而是尝试将业务操作建模为实体中的意图揭示方法。例如,您不会使用setter修改User
的{{1}},Street
和City
,而是调用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描述的状态。