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 形状:扁平、复杂/嵌套或两者的混合的主要内容,如果未能解决你的问题,请参考以下文章