DTO 形状:扁平、复杂/嵌套或两者的混合

Posted

技术标签:

【中文标题】DTO 形状:扁平、复杂/嵌套或两者的混合【英文标题】:DTO shape: flat, complex/nested, or a mixture of both 【发布时间】:2011-04-24 01:34:36 【问题描述】:

我有一个使用 DDD 方法(域驱动设计)的 MVC2 n 层应用程序(DAL、域、服务、MVC Web),具有带存储库的域模型。我的服务层使用请求/响应模式,其中请求和响应对象包含 DTO(数据传输对象)以将数据从一层编组到下一层,并通过 AutoMapper 的帮助完成映射.我的问题是:DTO 通常应该采用什么形状?它也可以有嵌套/复杂 DTO,还是应该严格地是一个平面投影? 或者可能两者兼而有之?另外,扁平 DTO 与更复杂/嵌套的 DTO 的主要原因是什么?

例如,假设我有一个域,如下所示:

public class Employee

    public string FirstName  get; set; 
    public string LastName  get; set; 
    public Company Company  get; set; 

public class Company

    public string Name  get; set; 
    public string Address  get; set; 
    public string City  get; set; 
    public string State  get; set; 

我想到了三种不同的方式来建模 Response 对象。

选项 1 - DRYest 选项:

public class GetEmployeeResponse

    public class EmployeeDTO  get; set;  // contains a CompanyDTO property

根据我所做的研究,DTO 采用与上述领域对象相似的形状是不合适的。

选项 2 - 域的扁平投影(反 DRY):

public class GetEmployeeResponse

    public string FirstName  get; set; 
    public string LastName  get; set; 
    public string CompanyName  get; set; 
    public string CompanyAddress  get; set; 
    public string CompanyCity  get; set; 
    public string CompanyState  get; set; 

这更简单,就像 DTO 显然应该的那样,但最终会产生更多的 DTO。

选项 3 - 两者兼而有之:

public class GetEmployeeResponse

    public EmployeeDTO Employee  get; set; 
    public CompanyDTO Company  get; set; 

这使代码更加枯燥、可重用和可管理,并且不会将我的域结构暴露给最终用户。另一个主要好处是其他响应,如GetCompanyResponse 可以简单地返回CompanyDTO,而无需复制所有这些属性,类似于选项2。你怎么看?您采取和/或为您工作过这些选项中的哪个(如果有)?如果这些请求/响应后来暴露为 WCF 服务方法,你的答案会改变吗?

【问题讨论】:

为什么首先要构建 n 层 MVC 应用程序?我并不是说这是错误的。只是好奇在域模型和 Web 层之间放置服务可以获得什么优势 我只想回复您的特定评论:“复制所有这些属性”。一旦您的系统达到一定的复杂度阈值,最好有一个在 DB 级别(通过视图或在您的 ORM 配置中)非规范化的专用读取模型。当我开始这样做时,它允许我构建更复杂的域模型,因为我不必担心为查询方面的事情而水合它们的费用。我的意思是,如果您只是要对多个模型进行非规范化,为什么还要对它们进行水合呢?让数据库这样做。无论如何,这就是它所擅长的。 @Szymon 拥有服务层有很多优势。对我来说,最大的优势是我可以将所有安全性放在一个层中,而不会让它泄漏到我的控制器中。 @Szymon 除了@Ryan 的 cmets,我的服务层 API 最终将作为 WCF 服务公开,供合作伙伴使用和开发。我的网络应用程序将简单地成为使用这些网络服务的另一个客户端。 @tbehunin 您如何知道您的合作伙伴会发现您为在 Web 界面中使用而设计的 API 有用?在我看来,机会很小。我宁愿直接将 UI 与域和构建的服务 API 连接起来,专注于外部系统的自动使用 【参考方案1】:

我个人的偏好是尽量保持平稳,只传输所需的数据。话虽如此,我过去曾使用过深度嵌套的 DTO,因为它在当时很有意义并且符合要求。所以我想它归结为“它取决于”。归根结底,选择对手头的应用程序有意义的东西。试图将数据硬塞进不符合您要实现的目标的 DTO 约定是没有意义的。

【讨论】:

Aka - 不要为了实现模棱两可的设计模式 (DTO) 而抛弃常识。 ;) 您如何在平面 DTO 中存储分层信息(产品类别)? @jfar 我关注的因素之一是应用程序的健谈性。如果网络上有大量流量(即客户端请求许多小信息)只是为了显示一页信息,我希望将其合并到一个信息请求中并以适合的格式返回数据. @jfar 如果它适合我​​可能会去规范化,以便您将类别作为产品的一部分。正如我在回答中所说,我更喜欢让它尽可能平坦,但这并不意味着它应该像煎饼一样平坦。如果具有层次结构的 DTO 可以更轻松地以您选择的语言编写和维护代码,那么我会像过去使用带有 MS InfoPath 的 Web 服务时那样选择该路线。在这种情况下,试图压平 DTO 是没有意义的。应用程序的数据需求定义了 DTO。

以上是关于DTO 形状:扁平、复杂/嵌套或两者的混合的主要内容,如果未能解决你的问题,请参考以下文章

WCF 服务:app.config 与属性或两者的混合

嵌套设置中的混合效应模型或多重回归比较

难以获得混合线a和指向ggplot2中颜色和形状的点图例

OpenGL GLSL 通过任意形状混合两个纹理

0.AutoMapper

重构复杂的 opengl 混合