El uso de Data Transfer Objects (DTO’s)

En muchas de nuestras aplicaciones, estamos usando ORM cómo Entity Framework. Los objetos (clases) de nuestra modelo E/R (DB) son mapeados mediante un modelo orientado objeto que representa sus relaciones físicas en formato lógico.

Estos objetos, que se pueden abstraer cómo entidades POCO de este ORM, pueden llegar a contener muchas relaciones entre los diferentes objetos dependiendo de la complejidad de nuestro modelo E/R.

En las tecnologías visibles para nuestros usuarios, es decir, las interfaces de usuario (UI) cómo puede ser ASP.NET MVC, Aplicaciones móviles… entre otros, necesitamos dar una experiencia rica, ágil y rápida teniendo en cuenta que en muchas ocasiones nuestro modelo de datos es complejo y la interfaz del usuario es sencilla.

Justo en este momento es dónde entran en contexto los Objeto de transferencia de datos (DTO con sus siglas en inglés) dónde nace (no es nuevo, este concepto lleva años con nosotros pero gana peso en las aplicaciones actuales :)) con el objetivo de minimizar el coste de la comunicación entre procesos y por lo tanto, la transferencia de datos entre estos en cada una de sus llamadas cliente – servidor minimizando así su tiempo de respuesta y transportando únicamente los datos necesarios para la operación destino.

La diferencia entre los objetos DTO y los objetos de negocio es que los primeros únicamente tienen el comportamiento de transformar los datos desde el origen y entregar los datos a su destino. Estos objetos son simples y sin lógica de negocio, es decir, son objetos que no están contenidos en nuestro dominio si no que se nutren de su resultado.

A la conclusión que podemos llegar es que si usamos las entidades POCO cómo DTO nos saltamos justo la S (SPR) de los principios SOLID que os explicava en un anterior post y le damos 2 responsabilidades diferentes a nuestro objeto: sirve de entidad del ORM y por otro de transferencia de datos.

Además darle dos responsabilidades a un objeto, obligas a que los procesos envíen gran parte la información que almacenas en la base de datos, y quizá solo hace falta una parte de esa información. Y con eso estarás enviando demasiada o poca información creando procesos muy poco eficientes.

¿Cuándo se debe usar DTO?
– Cuándo debamos reducir el nombre de llamadas al servidor.
– Cuándo debamos considerar el rendimiento y la latencia de las comunicaciones de la red.
– Cuándo debamos minimizar la transferéncia de datos.

¿Cómo se usan los DTO?
Los DTO no son mas que clases sencillas con propiedades get y set. Estas clases son llenadas en desde la capa de aplicación que estas obtienen los datos desde el repositorio a través de una llamada a nuestra DB.

Los DTO deben ser definidos en una librería a parte dentro de nuestro dominio pero sin formar parte de él pues carecen de comportamiento y en una capa superior, dónde recibimos la respuesta de la aplicación, debemos realizar la conversión de nuestra respuesta de entidad POCO a nuestro DTO.

Para ello podemos usar diferentes métodos pero en .NET y con las últimas versiones podemos usar dos formas de hacer esta conversión,
– La primera de ellas es mediante Automapper que es una librería que es capaz de convertir un objeto a otro mediante un mapeo (Lo podéis instalar mediante Nugget). Si en ambos objetos, las propiedades get y set tienen el mismo nombre, el mapeo es muy sencillo pero si no, nos permite manejar esa conversión de forma muy sencilla.

public static ContactDto Binding(Contact contact)
{
  ContactDto contactDto = new ContactDto();
  Mapper.CreateMap<Contact, ContactDto>()
        .ForMember(c => c.Name, dto => dto.MapFrom(co => co.Person.Name))
        .ForMember(c => c.FirstName, dto => dto.MapFrom(co => co.Person.FirstName))
        .ForMember(c => c.LastName, dto => dto.MapFrom(co => co.Person.LastName))
        .ForMember(c => c.Gender, dto => dto.MapFrom(co => co.Person.Gender))
        .ForMember(c => c.IdPerson, dto => dto.MapFrom(co => co.Person.IdPerson))
        .IgnoreAllNonExisting();
  Mapper.AssertConfigurationIsValid();
  contactDto = Mapper.Map<Contact, ContactDto>(contact);
  return contactDto;
}

A grandes rasgos, lo que nos permite hacer el objeto Mapper es crear un mapeo entre dos clases (Contact y ContactDto), le indicamos mediante .ForMember cómo debe ser la conversión (solo es necesario si es diferente) y le indicamos que IgnoreAllNonExisting, es decir, que no mapea lo que no exista. Finalmente hacemos un AssertConfigurationIsValid  que nos devuelve una excepción si no puede hacer la conversión.

Para terminar, hacemos el Map y obtenemos nuestro DTO con los datos que vamos a usar o representar y descartamos el resto.
En otro post, explicaré cómo usar Automapper a fondo pues da para escribir más de un post.

– La segunda de ellas, es mediante una consulta Linq to Objects y escojer que queremos devolver y que no.

var report = await _ourLayerApplication
.Contact
.Where(cnt => cnt.SequenceNumber == contactCode)
.Select(cnt => new ContactDTO
{
  Name = cnt.Person.Name,
  FirstName = cnt.Person.FirstName,
  LastName = cnt.Person.LastName,
  Gender = cnt.Person.Gender,
  IdPerson = cnt.Person.IdPerson
}).SingleOrDefaultAsync();

¿Cuál usar?
Personalmente, ambas formas nos proporcionan la misma potencia aunque al estar contextualizado en el entorno de EF y .NET la segunda forma no necesita del uso de librerías de terceros y la primera, debemos usar una librería externa y que a nivel de rendimiento, no nos oferecerá el mismo rendimiento que una consulta Linq to objects nativa de .NET.

En todo caso y resumiendo, lo que no debemos hacer es devolver los objetos obtenidos mediante consultas a la DB si usamos ORM cómo EF pues contienen sus relaciones y estas, pueden ser complejas, pesadas y transmitir datos que no son necesarios para nuestra aplicación, sobretodo, si su destino son entornos que deben ser fluidos cómo la web, el cloud y las app.

A desarrollar :)
Saludos!

4 pensamientos en “El uso de Data Transfer Objects (DTO’s)

  1. leo

    me parece interesante tu articulo, tengo una pregunta, cuando el dto retonar a la aplicacion (por ejemplo a una aplicacion web) retorna como dto , como puedo retornarlo en formato json , tengo que serializarlo?, gracias de antemano.

  2. Francesc Autor

    Buenas tardes,
    Si el DTO sube a una capa de ASP.NET MVC por ejemplo, este, ya será devuelto cómo JSON desde el Controller de forma automática. Si por ejemplo usas ASP.NET o WPF, deberás serializar el DTO antes de ser enviado a la UI.
    En estos casos, lo mejor es hacer una Web Api y comunicar tu aplicación a través de ella.
    Un saludo,

  3. Cristian Camilo Berrio Montoya

    Amigo me parece muy bien tu post, pero tengo algunas dudas respecto al uso, podrías hacer un pequeño ejemplo del uso, y otra cosa cuando utilizaríamos viewmodels y cuando Dto’s? muchas gracias.

  4. Francesc Autor

    Hola Cristian,
    Debes entender los ViewModels cómo una clase que tiene instancias de información (DTO’s) y métodos para presentar o tratar la información a mostrar en la interface. Por ejemplo, puedes tener un ViewModel que use “n” DTO’s para mostrar cierta información por pantalla en vez de usar las clases POCO generadas por algún ORM cómo EF. Un ejemplo clave de cuándo usar un DTO es el las arquitecturas orientadas a servicios. Nuestros endponints reciben información a través de una request y estos dan un response de lo que se solicita, dónde en su mayoría, no tienen que reciben toda la información de nuestro modelo si no que tan solo precisan una parte.
    Espero haber ayudado!
    Un saludo,

Deja un comentario

Tu dirección de correo electrónico no será publicada.