91

我见过很多与将DTO映射到域对象相关的问题,但我觉得他们没有回答我的问题。我以前用过很多方法,也有自己的看法,但我正在寻找更具体的方法。

情况:

我们有很多领域对象。我们正在使用 CSLA 模型,因此我们的域对象可能非常复杂,并且它们包含自己的数据访问权限。你不想在电线上传递这些。我们将编写一些新服务,这些服务将以多种格式(.Net、JSON 等)返回数据。出于这个(和其他原因),我们还创建了一个精简的数据传输对象以在网络上传递。

我的问题是:DTO 和 Domain 对象应该如何连接?

我的第一反应是使用Fowler,DTO 模式类型的解决方案。我已经看过很多次了,这对我来说是正确的。域对象不包含对 DTO 的引用。调用外部实体(“映射器”或“组装器”)从域对象创建 DTO。通常在域对象端有一个ORM。这样做的缺点是“映射器”对于任何实际情况都会变得极其复杂,并且可能非常脆弱。

提出的另一个想法是域对象“包含” DTO,因为它只是一个精益数据对象。域对象属性将在内部引用 DTO 属性,并且可以在需要时返回 DTO。我看不出这有什么问题,但感觉不对。我看过一些文章,使用NHibernate的人似乎使用了这种方法。

还有其他方法吗?以上方法之一值得使用吗?如果是或不是,为什么?

4

10 回答 10

44

当您仅支持单个映射时,将映射器置于域和 DTO 之间的好处并不明显,但随着映射数量的增加,将该代码与域隔离有助于使域更简单和更精简。您不会因为过多的额外重量而使您的域混乱。

就个人而言,我尝试将映射排除在我的域实体之外,并将责任放在我所谓的“管理器/服务层”中。这是一个位于应用程序和存储库之间的层,并提供诸如工作流协调之类的业务逻辑(如果您修改 A,您可能还必须修改 B,以便服务 A 可以与服务 B 一起使用)。

如果我有很多可能的结束格式,我可能会考虑创建一个可以使用访问者模式的可插入格式化程序,例如转换我的实体,但我还没有发现需要如此复杂的任何东西。

于 2009-03-24T16:47:52.050 回答
24

您可以使用自动映射器,例如Jimmy Bogard 编写的自动映射器,它在对象之间没有任何联系,并且依赖于遵守的命名约定。

于 2009-03-24T16:41:44.390 回答
9

将映射逻辑保留在实体内部意味着您的域对象现在知道它不需要知道的“实现细节”。通常,DTO 是您通往外部世界的网关(来自传入请求或通过从外部服务/数据库读取)。由于实体是业务逻辑的一部分,因此最好将这些详细信息保留在实体之外。

将映射保存在其他地方将是唯一的选择——但它应该去哪里呢?我已经尝试过引入映射对象/服务,但毕竟说了又做了,这似乎是过度工程(并且可能是)。我在使用 Automapper 等小型项目方面取得了一些成功,但像 Automapper 这样的工具也有其自身的缺陷。我很难找到与映射相关的问题,因为 Automapper 的映射是隐式的,并且与您的其余代码完全解耦(不像“关注点分离”,而更像是“上帝遗弃的映射在哪里”)所以他们有时很难追踪。并不是说 Automapper 没有它的用​​途,因为它有。我只是认为映射应该是尽可能明显和透明的东西,以避免出现问题。

我没有创建映射服务层,而是成功地将我的映射保存在我的 DTO 中。由于 DTO 始终位于应用程序的边界,因此可以让它们了解业务对象并弄清楚如何映射到它们。即使映射的数量扩展到合理的数量,它也可以干净地工作。所有映射都在一个地方,您不必在数据层、反腐败层或表示层内管理一堆映射服务。相反,映射只是委托给与请求/响应相关的 DTO 的实现细节。由于序列化程序通常仅在您通过网络发送属性和字段时对其进行序列化,因此您不应该遇到任何问题。就个人而言,我发现这是最干净的选择,根据我的经验,我可以说,

于 2019-06-21T22:23:48.180 回答
7

我们使用 T4 模板来创建映射类。

Pro's - 在编译时可用的人类可读代码,比运行时映射器更快。100% 控制代码(可以使用部分方法/模板模式来临时扩展功能)

Con's - 不包括某些属性、领域对象的集合等,学习 T4 语法。

于 2011-12-02T09:40:17.763 回答
4

您如何看待在 DTO 类中实现一个将域对象作为参数的构造函数?

说...像这样的东西

class DTO {

     // attributes 

     public DTO (DomainObject domainObject) {
          this.prop = domainObject.getProp();
     }

     // methods
}
于 2014-06-25T14:23:53.940 回答
1

另一种可能的解决方案:http: //glue.codeplex.com

特征:

  • 双向映射
  • 自动映射
  • 不同类型之间的映射
  • 嵌套映射和展平
  • 列表和数组
  • 关系验证
  • 测试映射
  • 属性、字段和方法
于 2011-04-22T08:37:05.357 回答
0

你也可以试试 Otis,一个对象到对象的映射器。概念类似于 NHibernate 映射(属性或 XML)。

http://code.google.com/p/otis-lib/wiki/GettingStarted

于 2009-06-30T21:22:42.647 回答
0

我可以推荐一个我创建的工具,它是托管在 CodePlex 的开源工具:EntitiesToDTOs

从 DTO 到实体的映射,反之亦然,是通过扩展方法实现的,这些方法构成了每一端的汇编器端。

您以如下代码结束:

Foo entity = new Foo();
FooDTO dto = entity.ToDTO();
entity = dto.ToEntity();

List<Foo> entityList = new List<Foo>();
List<FooDTO> dtoList = entityList.ToDTOs();
entityList = dtoList.ToEntities();
于 2012-09-07T23:46:51.750 回答
0

另一种选择是使用ModelProjector。它支持所有可能的场景,并且非常易于使用且占用空间极小。

于 2018-08-08T15:15:23.427 回答
0

为此,我们可以使用 Factory、Memento 和 Builder 模式。工厂隐藏有关如何从 DTO 创建域模型实例的详细信息。Memento 将负责域模型与 DTO 的序列化/反序列化,甚至可以访问私有成员。Builder 将允许从 DTO 映射到具有流畅界面的域。

于 2018-11-01T13:56:09.257 回答