- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我已经阅读了几篇关于将域对象转换为 DTO 的文章和 Stackoverflow 帖子,并在我的代码中进行了尝试。当谈到测试和可扩展性时,我总是面临一些问题。我知道以下三种将域对象转换为 DTO 的可能解决方案。大多数时候我都在使用 Spring。
方案一:服务层的私有(private)方法进行转换
第一个可能的解决方案是在服务层代码中创建一个小的“帮助程序”方法,它将检索到的数据库对象转换为我的 DTO 对象。
@Service
public MyEntityService {
public SomeDto getEntityById(Long id){
SomeEntity dbResult = someDao.findById(id);
SomeDto dtoResult = convert(dbResult);
// ... more logic happens
return dtoResult;
}
public SomeDto convert(SomeEntity entity){
//... Object creation and using getter/setter for converting
}
}
优点:
缺点:
new SomeEntity()
在私有(private)方法中使用,如果对象嵌套很深,我必须提供我的 when(someDao.findById(id)).thenReturn(alsoDeeplyNestedObject)
的足够结果如果转换也溶解嵌套结构,则避免 NullPointers解决方案 2:DTO 中用于将域实体转换为 DTO 的附加构造函数
我的第二个解决方案是向我的 DTO 实体添加一个额外的构造函数,以转换构造函数中的对象。
public class SomeDto {
// ... some attributes
public SomeDto(SomeEntity entity) {
this.attribute = entity.getAttribute();
// ... nesting convertion & convertion of lists and arrays
}
}
优点:
缺点:
new SomeDto()
在服务代码中,因此我必须提供正确的嵌套对象结构,因为我的 someDao
mock 。 解决方案 3:使用 Spring 的 Converter 或任何其他外部化 Bean 进行此转换
如果最近看到 Spring 出于转换原因提供了一个类:Converter<S, T>
但是这个解决方案代表每个进行转换的外部化类。使用此解决方案,我将转换器注入(inject)到我的服务代码中,并在我想将域实体转换为我的 DTO 时调用它。
优点:
缺点:
对于我的问题,你们有更多的解决方案吗?你们是如何处理的?您是否为每个新的域对象创建一个新的转换器,并且可以“生活”与项目中的类数量?
提前致谢!
最佳答案
Solution 1: Private method in the service layer for converting
我猜解决方案 1 不会很好用,因为您的 DTO 是面向域的而不是面向服务的。因此,它们很可能用于不同的服务。所以映射方法不属于一个服务,因此不应该在一个服务中实现。您将如何在另一个服务中重用映射方法?
如果您为每种服务方法使用专用的 DTO,则 1. 解决方案会很有效。但最后会详细介绍。
Solution 2: Additional constructor in the DTO for converting domain entity to DTO
通常是一个不错的选择,因为您可以将 DTO 视为实体的适配器。换句话说:DTO 是实体的另一种表示。此类设计通常会包装源对象并提供方法,让您可以从另一个角度查看被包装的对象。
但是 DTO 是一个数据 transfer 对象,因此它迟早会被序列化并通过网络发送,例如使用 spring's remoting capabilities .在这种情况下,接收此 DTO 的客户端必须对其进行反序列化,因此需要其类路径中的实体类,即使它仅使用 DTO 的接口(interface)。
Solution 3: Using Spring's Converter or any other externalized Bean for this converting
解决方案 3 也是我更喜欢的解决方案。但我会创建一个 Mapper<S,T>
负责从源映射到目标的接口(interface),反之亦然。例如
public interface Mapper<S,T> {
public T map(S source);
public S map(T target);
}
可以使用像 modelmapper 这样的映射框架来完成实现。 .
你还说每个实体都有一个转换器
doesn't "scale" that much as my domain model grows. With a lot of entities I have to create two converters for every new entity (-> converting DTO entitiy and entitiy to DTO)
我怀疑您只需要为一个 DTO 创建 2 个转换器或一个映射器,因为您的 DTO 是面向域的。
一旦您开始在另一个服务中使用它,您就会认识到另一个服务通常应该或不能返回第一个服务所做的所有值。您将开始为其他服务实现另一个映射器或转换器。
如果我从专用或共享 DTO 的优缺点开始,这个答案会很长,所以我只能请你阅读我的博客 pros and cons of service layer designs .
编辑
About the third solution: where do you prefer to put the call for the mapper?
在用例之上的层。 DTO 是数据传输对象,因为它们将数据打包成最适合传输协议(protocol)的数据结构。因此,我称该层为传输层。该层负责将用例的请求和结果对象从传输表示映射到传输表示,例如json 数据结构。
编辑
I see you're ok with passing an entity as a DTO constructor parameter. Would you also be ok with the opposite? I mean, passing a DTO as an Entity constructor parameter?
一个好问题。相反的对我来说是不行的,因为我会在实体中引入对传输层的依赖。这意味着传输层的变化会影响实体,我不希望更详细的层的变化影响更多的抽象层。
如果你需要将数据从传输层传递到实体层,你应该应用依赖倒置原则。
引入一个接口(interface),该接口(interface)将通过一组getter返回数据,让DTO实现它并在实体构造函数中使用该接口(interface)。请记住,此接口(interface)属于实体层,因此不应依赖于传输层。
interface
+-----+ implements || +------------+ uses +--------+
| DTO | ---------------||-> | EntityData | <---- | Entity |
+-----+ || +------------+ +--------+
关于java - 如何在考虑可扩展性和可测试性的同时正确地将域实体转换为 DTO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47843039/
这是我的本地域名 http://10.10.1.101/uxsurvey/profile/dashboard 在 Controller 中,我为用户列表设置了一个操作 redirect(control
要处理 Canonical URL,最佳做法是执行 301 重定向还是更好地为 www 和非 www 域使用相同的 IP 地址? 例如: 想要的规范 URL/域是 http://example.com
1 内网基础 内网/局域网(Local Area Network,LAN),是指在某一区域内有多台计算机互联而成的计算机组,组网范围通常在数千米以内。在局域网中,可以实现文件管理、应用软件共享、打印机
1 内网基础 内网/局域网(Local Area Network,LAN),是指在某一区域内有多台计算机互联而成的计算机组,组网范围通常在数千米以内。在局域网中,可以实现文件管理、应用软件共享、打印机
我想创建一个 weblogic 集群,其中有两个托管服务器,每个服务器在物理上独立的远程计算机上运行 根据weblogic文档 All Managed Servers in a cluster mus
我正在运行 grails 3.1.4,但在创建允许我将多个域对象绑定(bind)到其他几个域对象的模式时遇到了问题。作为我正在尝试做的一个例子: 我有三个类(class)。书籍、作者和阅读列表。 作者
我试图使用@count函数来根据它获取数据,但是在没有崩溃报告的情况下它以某种方式崩溃了。 这是代码 class PSMedia: Object { @objc dynamic var id
有谁知道是否有办法只输入字母字符而不输入数字?我想过这样的事情 CREATE DOMAIN countryDomain AS VARCHAR(100) CHECK( VALUE ??? );
我的代码: const checkoutUrl = 'https://example.com/checkout/*' window.onload = startup() function st
一些不是我编写的应用程序,也不是用 PHP 编写的,它为域 www.example.com 创建了一个 cookie。 我正在尝试替换该 cookie。所以在 PHP 中我做到了: setcookie
什么是 oauth 域?是否有任何免费的 oauth 服务?我可以将它用于 StackApps registration 吗? ?我在谷歌上搜索了很多,但找不到答案。 最佳答案 这是redirect_
自从 In October 2009, the Internet Corporation for Assigned Names and Numbers (ICANN) approved the cre
我使用 apache 作为我的应用程序 Web 服务器的代理,并希望即时更改与 sessionid cookie 关联的域名。 该cookie有一个与之关联的.company.com域,我想使用apa
我只想托管一个子域到cloudflare。我不想将主域名的域名服务器更改为他们的域名服务器。真的有可能吗? 最佳答案 是的,这是可能的,但是需要通过CloudFlare合作伙伴进行设置,或者您需要采用
When using socket in the UNIX domain, it is advisable to use path name for the directory directory m
想象两个共享一个域类的 Grails 应用程序。也许是 Book 域类。 一个应用程序被标识为数据的所有者,一个应用程序必须访问域数据。类似于亚马逊和亚马逊网络服务。 我想拥有的应用程序将使用普通的域
我有一个包含字段“URL”的表单。第一部分需要用户在文本框中填写。第二部分是预定义的,显示在文本框的右侧。 例如,用户在文本框中输入“test”。第二部分预定义为“.example.com”。因此,总
如果我要关闭并取消分配 azure 中的域 Controller ,从而生成新的 vm Generationid,我需要采取哪些步骤来恢复它? 最佳答案 what steps do I need to
我想尝试使用 Azure 作为托管提供商(我有一个域)。我读过那篇文章https://learn.microsoft.com/en-us/azure/app-service-web/web-sites
所以.... 我想知道是否有人可以在这方面协助我? 基本上,我已经创建了一个自托管的Docker容器,用作构建代理(Azure DevOps) 现在,我已经开始测试代理,并且由于我们的放置文件夹位于W
我是一名优秀的程序员,十分优秀!