【发布时间】: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 连接起来,专注于外部系统的自动使用
标签: c# asp.net-mvc domain-driven-design automapper dto