在大型.NET项目中管理DTO和映射

在大型.NET项目中管理DTO和映射,.net,mapping,dto,.net,Mapping,Dto,我和我的团队正在构建一个大型的.NET WinForms应用程序。该应用程序使用各种“服务”从我们的数据库获取数据。每个“服务”都存在于自己的解决方案中,并处理特定类型的数据。例如,我们的“ContactsService”负责将联系人检索/保存到数据库中 通常,我们一直在为每个服务构建DTO。因此,我们可能有一个“ContactDTO”,它对联系人上的每一条数据都有简单的字符串属性。现在,我们还有一个业务层的“Contact”类,它具有完全相同的属性,可能还有一些额外的方法和一些业务逻辑。除此之

我和我的团队正在构建一个大型的.NET WinForms应用程序。该应用程序使用各种“服务”从我们的数据库获取数据。每个“服务”都存在于自己的解决方案中,并处理特定类型的数据。例如,我们的“ContactsService”负责将联系人检索/保存到数据库中

通常,我们一直在为每个服务构建DTO。因此,我们可能有一个“ContactDTO”,它对联系人上的每一条数据都有简单的字符串属性。现在,我们还有一个业务层的“Contact”类,它具有完全相同的属性,可能还有一些额外的方法和一些业务逻辑。除此之外,“ContactsService”还有自己的Contact类别,它是从ContactDTO中水合而成的

管理我们所有的DTO和映射已经成为一个巨大的难题。当前,发送要存储在数据库中的联系人如下所示:

  • 将客户端联系人映射到ContactDTO
  • 将ContactD映射到服务联系人
  • 保存联系人
  • 将服务联系人映射到ContactDTO
  • 将ContactDTO映射到客户端联系人
这感觉糟透了。如果我们向客户联系人类添加属性,我们必须在3-4个位置添加属性和映射


我们做错了什么?我们如何让生活变得更轻松?使用Json.NET之类的东西并拥有Json DTO会更简单吗?我们查看了AutoMapper,但一些团队成员认为它太复杂了。

AutoMapper并不特别复杂。如果您遵循约定,例如,Contact.Address1在DTO上变为ContactAddress1,则除了调用Mapper.Map之外,您不必编写太多代码。或者,您可以使用代码生成,但管理更改仍然很棘手

我能问一下,为什么您觉得需要一个联系人和一个服务联系人?你能不能把服务联系人传给别人?我知道这不是最佳实践,但它可能会使你免于RSI


编辑:忽略我的最后一点-出于某种原因,我以为您正在将服务联系人映射到一个数据库实体,如NHibernate/entity Framework

我经常遇到这种情况,但在我的情况下,我选择接受它,因为使用DTO的决定是有意的-我想要我的服务、客户端、代理,和合同组件要干净地分开

使用WCF时,我喜欢的布局如下(使用您的联系人示例):

  • 客户端程序集
    • 联系人(具有客户-y特征)
  • 共享合同程序集
    • 联系人(约定的共同DTO)
  • 代理程序集
    • 使用共享合同程序集中的联系人
  • 服务组合
    • 联系人(具有service-y业务逻辑特征,例如,这可能是ORM层(如实体框架)公开的类型)
我现在正在共享服务和客户之间的合同。如果需要独立地对它们进行版本设置,那么我可以创建共享契约程序集的副本,并将代理程序集重新定位为使用副本,然后独立地修改这两个契约程序集。但在我工作过的大多数情况下,我同时拥有客户机和服务,因此在两者之间共享合同组件是很方便的

这是我在做出用DTO隔离组件的体系结构决策时所能想到的唯一优化,至少在不使用代码生成工具的情况下(我不知道有什么好的工具,但不必研究它们)


编辑:当不使用WCF时,您显然不需要“代理”程序集。

需要考虑一些加快流程的事情:

我编写了一个代码生成器,您可以从数据库中选择表和列,并让它生成一个C#DTO。这样可以节省大量不必要的键入,并且可以更快地生成DTO。提前一点时间,但是当您有一个包含20列的表需要映射时,它会有所帮助

我还编写了代码生成器,将DTO映射到存储过程,以进行保存、删除和查询操作。这又一次节省了时间,因为它们中的许多最终都非常相似。如果你编写了很多繁琐的“咕噜”代码,考虑一个代码生成器来做。 在后端使用实体框架或ORM映射器。这可以节省很多时间,但您必须投资于ORM知识并了解它是如何工作的

创建一组从客户端到数据库使用的通用DTO。在某些情况下,当客户端需要代理或更小的DTO时,这可能不实用,但您可以尝试将一些常见的DTO从客户端一直传递回服务器

删除一些图层。我知道这听起来有点反模式,但在某些情况下洋葱不必那么厚