¿Mejores prácticas para asignar DTO al objeto de dominio?

He visto muchas preguntas relacionadas con la asignación de DTO a objetos de dominio, pero no creo que hayan respondido mi pregunta. He usado muchos métodos antes y tengo mis propias opiniones, pero estoy buscando algo un poco más concreto.

La situación:

Tenemos muchos objetos de dominio. Estamos utilizando un modelo de CSLA para que nuestros objetos de dominio puedan ser bastante complejos y que tengan su propio acceso a los datos. No quiere pasar esto por el cable. Vamos a escribir algunos servicios nuevos que devolverán datos en varios formatos (.Net, JSON, etc.). Por esto (y por otros motivos), también estamos creando un objeto de transferencia de datos delgado para pasar por el cable.

Mi pregunta es ¿cómo deberían estar conectados el DTO y el objeto de dominio?

Mi primera reacción es utilizar una solución de tipo patrón Fowler, DTO . He visto esto muchas veces y me parece bien. El objeto de dominio no contiene ninguna referencia al DTO. Se llama a una entidad externa (un “asignador” o “ensamblador”) para crear un DTO a partir de un objeto de dominio. Normalmente hay un ORM en el lado del objeto del dominio. La desventaja de esto es que el “mapeador” tiende a ser extremadamente complejo para cualquier situación real y puede ser muy frágil.

Otra idea presentada es que el objeto de dominio “contenga” el DTO, ya que es solo un objeto de datos pobre. Las propiedades del objeto de dominio hacen referencia internamente a las propiedades de DTO y pueden simplemente devolver el DTO si así lo solicita. No veo problemas con esto, pero se siente mal. He visto algunos artículos donde las personas que usan NHibernate parecen usar este método.

¿Hay otras formas? ¿Vale la pena usar una de las formas anteriores? Si es así o no, ¿por qué?

Gracias por cualquier idea de antemano.

Una ventaja de tener un asignador que se encuentra entre su dominio y su DTO no es tan importante cuando solo admite una sola asignación, pero a medida que aumenta el número de asignaciones, tener ese código aislado del dominio ayuda a mantener el dominio más simple y ágil. No abarrotarás tu dominio con mucho peso extra.

Personalmente, bash mantener el mapeo fuera de las entidades de mi dominio y asumo la responsabilidad en lo que llamo “capa de administrador / servicio”. Esta es una capa que se encuentra entre la aplicación y el (los) repository (es) y proporciona lógica de negocios como la coordinación del flujo de trabajo (si modifica A, también deberá modificar B para que el servicio A funcione con el servicio B).

Si tuviera muchos formatos de finalización posibles, podría considerar la creación de un formateador enchufable que pudiera usar el patrón Visitor, por ejemplo para transformar mis entidades, pero aún no he encontrado la necesidad de algo tan complejo.

Puede utilizar un Automapper como el escrito por Jimmy Bogard que no tiene conexión entre los objetos y se basa en las convenciones de nombres que se cumplen.

Usamos plantillas T4 para crear las clases de mapeo.

Pro’s: código legible por humanos disponible en tiempo de comstackción, más rápido que un mapeador de tiempo de ejecución. 100% de control sobre el código (puede usar métodos parciales / patrón de plantilla para extender la funcionalidad en una base ad-hoc)

Con’s – excluyendo ciertas propiedades, colecciones de objetos de dominio, etc., aprendiendo la syntax T4.

¿Cómo ve implementar un constructor dentro de la clase DTO que toma como parámetro un objeto de dominio?

Diga … Algo como esto

class DTO { // attributes public DTO (DomainObject domainObject) { this.prop = domainObject.getProp(); } // methods } 

Otra posible solución: http://glue.codeplex.com .

caracteristicas:

  • Mapeo bidireccional
  • Mapeo automático
  • Mapeo entre diferentes tipos
  • Asignación y astackmiento nesteds
  • Listas y matrices
  • Verificación de relaciones
  • Probando el mapeo
  • Propiedades, campos y métodos

También puedes probar Otis, un mapeador objeto a objeto. Los conceptos son similares al mapeo de NHibernate (atributo o XML).

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

Puedo sugerir una herramienta que he creado y es de código abierto alojado en CodePlex: EntitiesToDTOs .

El mapeo de DTO a Entity y viceversa se implementa mediante métodos de extensión, estos componen el lado del Ensamblador de cada extremo.

Usted termina con un código como:

 Foo entity = new Foo(); FooDTO dto = entity.ToDTO(); entity = dto.ToEntity(); List entityList = new List(); List dtoList = entityList.ToDTOs(); entityList = dtoList.ToEntities(); 

¿Por qué no podemos hacer esto?

 class UserDTO { } class AdminDTO { } class DomainObject { // attributes public DomainObject(DTO dto) { this.dto = dto; } // methods public function isActive() { return (this.dto.getStatus() == 'ACTIVE') } public function isModeratorAdmin() { return (this.dto.getAdminRole() == 'moderator') } } userdto = new UserDTO(); userdto.setStatus('ACTIVE'); obj = new DomainObject(userdto) if(obj.isActive()) { //print active } admindto = new AdminDTO(); admindto.setAdminRole('moderator'); obj = new DomainObject(admindto) if(obj.isModeratorAdmin()) { //print some thing } 

@FrederikPrijck (o) alguien: por favor sugiera. En el ejemplo anterior, DomainObject depende de DTO. De esta forma puedo evitar el código para hacer el mapeo de dto <-> domainobject.

o la clase DomainObject puede extender la clase DTO?

Otra opción sería usar ModelProjector . Es compatible con todos los escenarios posibles y es muy fácil de usar con un espacio mínimo.