He visto muchas preguntas relacionadas con la asignación de DTO a objetos de dominio, pero no sentí que respondieran a 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 CSLA, por lo que nuestros objetos de dominio pueden ser bastante complejos y contienen su propio acceso a datos. No conviene pasarlos por el cable. Vamos a escribir algunos servicios nuevos que devolverán datos en varios formatos (.Net, JSON, etc.). Por esta (y otras razones) también estamos creando un objeto de transferencia de datos esbelto para pasar por el cable.
Mi pregunta es: ¿Cómo se deben conectar el objeto DTO y el dominio?
Mi primera reacción es usar una solución de tipo patrón DTO de Fowler . 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 "mapeador" o "ensamblador") para crear un DTO a partir de un objeto de dominio. Normalmente hay un ORM en el lado del objeto de dominio. La desventaja de esto es que el "mapeador" tiende a volverse 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 ajustado. Las propiedades del objeto de dominio harían referencia internamente a las propiedades del DTO y podrían devolver el DTO si se lo solicita. No veo ningún problema con esto, pero se siente mal. He visto algunos artículos en los que las personas que utilizan NHibernate parecen utilizar este método.
¿Hay otras formas? ¿Vale la pena usar una de las formas anteriores? Si es así o no, ¿por qué?
fuente
Respuestas:
Un beneficio de tener un mapeador que se encuentra entre su dominio y su DTO no es tan aparente cuando solo admite un único mapeo, pero a medida que aumenta el número de mapeos, 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, trato de mantener el mapeo fuera de las entidades de mi dominio y pongo la responsabilidad en lo que llamo "Capa de Administrador / Servicio". Esta es una capa que se encuentra entre la aplicación y el (los) repositorio (s), y proporciona lógica empresarial como la coordinación del flujo de trabajo (si modifica A, es posible que también deba modificar B para que el servicio A funcione con el Servicio B).
Si tuviera muchos formatos finales posibles, podría considerar la creación de un formateador conectable que pudiera usar el patrón Visitor, por ejemplo, para transformar mis entidades, pero todavía no he encontrado la necesidad de algo tan complejo.
fuente
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 nomenclatura que se cumplen.
fuente
Usamos plantillas T4 para crear las clases de mapeo.
Pro's: código legible por humanos disponible en tiempo de compilación, más rápido que un mapeador en tiempo de ejecución. Control del 100% sobre el código (puede utilizar métodos parciales / patrón de plantilla para ampliar la funcionalidad de forma ad-hoc)
Contras: excluir ciertas propiedades, colecciones de objetos de dominio, etc., aprender la sintaxis T4.
fuente
Mantener la lógica de mapeo dentro de su entidad significa que su Objeto de Dominio ahora es consciente de un "detalle de implementación" que no necesita conocer. Generalmente, un DTO es su puerta de entrada al mundo exterior (ya sea desde una solicitud entrante o mediante una lectura de un servicio / base de datos externo). Dado que la entidad es parte de su lógica empresarial, probablemente sea mejor mantener esos detalles fuera de la entidad.
Mantener el mapeo en otro lugar sería la única alternativa, pero ¿a dónde debería ir? Intenté introducir objetos / servicios de mapeo pero, después de todo lo dicho y hecho, parecía una sobreingeniería (y probablemente lo fue). He tenido cierto éxito con Automapper y demás para proyectos más pequeños, pero las herramientas como Automapper tienen sus propios inconvenientes. He tenido algunos problemas bastante difíciles de encontrar relacionados con las asignaciones porque las asignaciones de Automapper están implícitas y están completamente desacopladas del resto de su código (no como una "separación de preocupaciones", sino más bien como un "dónde vive el mapeo olvidado de Dios"), por lo que a veces puede ser difícil de localizar. Por no decir que Automapper no tiene sus usos, porque los tiene. Creo que el mapeo debería ser algo tan obvio y transparente como sea posible para evitar problemas.
En lugar de crear una capa de servicio de mapeo, he tenido mucho éxito al mantener mis mapeos dentro de mis DTO. Dado que los DTO siempre se ubican en el límite de la aplicación, pueden conocer el Business Object y descubrir cómo mapear desde / hacia ellos. Incluso cuando el número de asignaciones escala a una cantidad razonable, funciona de forma limpia. Todos los mapeos están en un solo lugar y no tiene que administrar un montón de servicios de mapeo dentro de su capa de datos, capa anticorrupción o capa de presentación. En cambio, el mapeo es solo un detalle de implementación delegado al DTO involucrado con la solicitud / respuesta. Dado que los serializadores generalmente solo serializan propiedades y campos cuando los envía a través del cable, no debería tener ningún problema. Personalmente, he encontrado que esta es la opción más limpia y puedo decir, en mi experiencia,
fuente
¿Cómo ve implementar un constructor dentro de la clase DTO que toma como parámetro un objeto de dominio?
Di ... algo como esto
class DTO { // attributes public DTO (DomainObject domainObject) { this.prop = domainObject.getProp(); } // methods }
fuente
DTO
y elDomainObject
, básicamente nos esforzamos en que este problema del DTO depende del objeto de dominio, por lo que todo el "trabajo de construcción" se realiza en una capa intermedia (clase) llamadamapper
, que depende de ambos DTO y DomainObjects. Entonces, ¿cuál es el mejor enfoque, o generalmente el más recomendable, para este asunto? Solo pido asegurarme de que se entendió el punto.Otra posible solución: http://glue.codeplex.com .
caracteristicas:
fuente
También puede probar Otis, un mapeador de objeto a objeto. Los conceptos son similares al mapeo NHibernate (atributo o XML).
http://code.google.com/p/otis-lib/wiki/GettingStarted
fuente
Puedo sugerir una herramienta que creé y es de código abierto alojada en CodePlex: EntitiesToDTOs .
El mapeo de DTO a Entity y viceversa se implementa mediante métodos de extensión, estos componen el lado de ensamblador de cada extremo.
Terminas con un código como:
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();
fuente
¿Por qué no podemos hacer así?
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: sugiera. En el ejemplo anterior, DomainObject depende de DTO. De esta manera puedo evitar que el código haga el mapeo del dto <--> domainobject.
o la clase DomainObject puede extender la clase DTO?
fuente
Otra opción sería utilizar ModelProjector . Es compatible con todos los escenarios posibles y es muy fácil de usar con una huella mínima.
fuente
Podemos usar el patrón Factory, Memento y Builder para eso. Factory oculta los detalles sobre cómo crear una instancia de modelo de dominio desde DTO. Memento se encargará de la serialización / deserialización del modelo de dominio hacia / desde DTO e incluso puede acceder a miembros privados. El constructor permitirá el mapeo de DTO al dominio con una interfaz fluida.
fuente