我们应该如何处理DTO?

时间:2017-05-19 07:59:20

标签: design-patterns dto

我有2个表,PatientRegistration,关系是一对多的。

在我想要编辑注册的注册模块中,我调用GetRegistrationByID(int id)按ID获取数据,然后选择PatientCodePatientName并将其解析为DTO。

在另一个模块中,我重复使用GetRegistrationByID(int id)但我需要有关患者信息的更多信息,例如性别,出生地点和出生日期,地址,村庄,地区,省份和电话号码。

对于这种情况,我有2个选项,更改RegistrationDTO以包含更多患者的信息,但是当我调用GetRegistrationByID(int id)时注册模块的结果是注册模块变得更大。因为我只需要PatientCodePatientName,现在有额外的信息是不必要的。

第二个选项是我创建另一个方法GetPatientInfoByRegistrationID(int id)但结果是有两次往返数据库。我认为它违反了DTO原则

  

data transfer object(DTO 1 [2])是一个携带数据的对象   进程之间。其使用的动机是沟通   进程之间通常采用远程接口(例如,   网络服务),每次通话都是一项昂贵的操作。[2]因为   每次通话的大部分费用都与往返有关   客户端和服务器之间的时间,减少数量的一种方法   调用是使用聚合数据的对象(DTO)   可能会被多次通话转移,但这是有效的   只有一个电话。[2]

我试图学习如何使代码更好,我应该选择哪一个?请添加解释为何更好

1 个答案:

答案 0 :(得分:1)

费用可能没有您想象的那么大。仔细检查此部分:

  

因为每次调用的大部分成本都与客户端和服务器之间的往返时间有关,所以减少调用次数的一种方法是使用聚合数据的对象(DTO)已被多次通话转移,但只能通过一次通话服务。

这告诉你的是DTO用于服务器和某个客户端之间的通信,这可能包括网络开销(我说可能因为在某些情况下它可能是同一个服务器,例如DTO用于填充服务器端数据,同时生成HTML以返回浏览器客户端)。这就是为什么您希望将所需的信息包含在单个DTO中,而不是单独调用所有内容。例如,如果某个客户端需要注册患者信息,您希望避免让他们需要进行两次单独的调用,这就是您返回DTO中捆绑的数据的原因。否则你将有两次完整的往返旅行。但是,这并不意味着您需要不惜一切代价避免多个数据库查询。 DTO是在服务器端组成的,服务器上用于创建DTO的两个数据库查询并不像要求两个完整的客户端/服务器往返那样引人注目。

另一个考虑因素是,通常甚至不需要多个数据库查询。对象关系映射框架(例如Java Persistence API)通常允许您映射实体之间的关系,并指定是否应该懒惰地(仅在请求时)或急切地获取它们。 ORM可以通过使用连接来优化提取,以仅需要单个查询。仅仅因为来自DTO中多个实体的信息,并不意味着它必然需要多个数据库查询。

然后为您的DTO设计。所有信息不需要在一个单独的类中。 DTO可以镜像持久化实体及其关系。在您的情况下,您有一个PatientRegistration表,因此您可以拥有相应的DTO类,例如PatientDTORegistrationDTO,其中患者DTO可以拥有注册列表,并且注册DTO为相关患者的字段。这样的组合可以更容易地获取隔离数据(例如,如果您只需要患者数据,而不是注册)并重新使用类。

对于不同的数据集,您不一定需要不同的DTO。仅仅因为一个呼叫应该只包括患者姓名和代码,而另一个呼叫包含更多信息,并不意味着您需要单独的DTO类。只需定义一个可以保存所有信息(用于其相应实体)的类,并只填写所需的内容。毕竟,客户端通常知道它想要从呼叫中得到什么。如果您希望能够区分由于数据库不在数据库中而丢失的数据,以及那些根本没有映射的数据,您可以在每个字段中使用一些标记来指示它是否应该是是否设定。或者字段类型可能是一些包装对象,它在设置时会被标记,所以如果它是null或其他一些默认值,你现在就有意或无意。

最后,DTO不一定需要遵循实体的结构或属性名称。它们首先是为客户设计的,所以要为此设计。 DTO可以是抽象,以隐藏客户不需要知道的持久结构。但实际上,如果实体和DTO保持相似(即使不相同),通常也不会产生混淆。精心设计的实体无论如何都将具有清晰的结构和可理解的属性。