.net 将DTO映射到域对象的最佳实践?

.net 将DTO映射到域对象的最佳实践?,.net,asp.net,design-patterns,dto,.net,Asp.net,Design Patterns,Dto,我看到了很多与映射到域对象相关的问题,但我觉得它们没有回答我的问题。我以前用过很多方法,也有自己的观点,但我想找一些更具体的方法 情况: 我们有许多域对象。我们使用的是CSLA模型,因此我们的域对象可能非常复杂,并且它们包含自己的数据访问。你不想在电线上传递这些。我们将编写一些新的服务,这些服务将以多种格式返回数据(.Net、JSON等)。出于这个原因(以及其他原因),我们还创建了一个精简的数据传输对象,以便在网络上传递 我的问题是:DTO和域对象应该如何连接? 我的第一反应是使用一种新的方法。

我看到了很多与映射到域对象相关的问题,但我觉得它们没有回答我的问题。我以前用过很多方法,也有自己的观点,但我想找一些更具体的方法

情况:

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

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

我的第一反应是使用一种新的方法。我已经看过很多次了,我觉得这是对的。域对象不包含对DTO的引用。调用外部实体(“映射器”或“汇编程序”)从域对象创建DTO。通常在域对象端有一个。这样做的缺点是,“映射器”对于任何实际情况都会变得极其复杂,并且可能非常脆弱

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


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

您可以使用自动映射器,例如,它在对象之间没有连接,并且依赖于遵守命名约定。

在您的域和DTO之间有一个映射器的好处在您只支持单个映射时并不明显,但是随着映射数量的增加,将代码与域隔离有助于使域更简单、更精简。你不会因为额外的重量而使你的域名变得杂乱无章


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


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

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


另一种可能的解决方案:

特点:

  • 双向映射
  • 自动绘图
  • 不同类型之间的映射
  • 嵌套映射与展平
  • 列表和数组
  • 关系核实
  • 测试映射
  • 属性、字段和方法

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

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


Con's-排除某些属性、域对象集合等,学习T4语法。

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

从DTO到实体以及从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();
Foo entity=new Foo();
FooDTO dto=entity.ToDTO();
实体=dto.ToEntity();
List entityList=新列表();
List-dtoList=entityList.ToDTOs();
entityList=dtoList.ToEntities();

您认为如何在DTO类中实现一个构造函数,将域对象作为参数

说。。。像这样的

class DTO {

     // attributes 

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

     // methods
}

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

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

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

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

我没有创建映射服务层,而是成功地将映射保存在DTO中。