AutoMapper (I) Flattening

Antes de escribir sobre este proyecto, he realizado una búsqueda en Geeks.ms y no he encontrado nada, así que empezaremos desde cero para que todo el mundo la conozca.

¿Qué es AutoMapper?

Básicamente y sin complicar mucho la definición, sirve para realizar mapeos entre objetos .NET usando fluent interfaces y convention over configuration, o lo que es lo mismo, interfaces fluidas y convenciones predifinidas en su API en vez del uso de ficheros de configuración, aunque esto no quita que podamos configurarlo libremente como veremos más adelante. Nos evita tareas repetivivas y aburridas como es la transformación de objetos entre capas, aplicaciones… de manera automática.

Vamos a ver un primer ejemplo de la funcionalidad más básica o lo que se conoce como Flattening (Podríamos traducirlo como proyección plana pero suena fatal y creo que en este caso queda mejor mapeo por defecto, es decir basandonos en sus convenciones)

Para instalar AutoMapper podéis usar NuGet:

image

Partimos de unas entidades de dominio  de ejemplo como es una factura, el cliente, las líneas de factura y los productos:

public class Invoice

{

    public Guid Id { get; set; }

    public Customer Customer { get; set; }

    public List<InvoiceLine> Lines { get; set; }

 

    public decimal GetTotal()

    {

        return Lines.Sum(l => l.Product.Price*l.Quantity);

    }

}

 

public class Customer

{

    public Guid Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

}

 

public class InvoiceLine

{

    public Guid Id { get; set; }

    public Product Product { get; set; }

    public int Quantity { get; set; }

 

    public decimal GetTotal()

    {

        return Product.Price*Quantity;

    }

}

 

public class Product

{

    public decimal Price { get; set; }

    public string Name { get; set; }

}

 
Tenemos como requerimiento comunicarnos con un ERP y enviarle cierta información, como es el Id de la factura, el Id del cliente y el total de la factura. Para estos casos no vamos a enviar información de nuestro dominio al servicio del ERP que nada tiene que ver con nuestra aplicación, y además solo hace falta enviar un objeto con 3 propiedades y para ello vamos a usar un DTO:
 
public class InvoiceDto

{

    public Guid Id { get; set; }

    public Guid CustomerId { get; set; }

    public decimal Total { get; set; }

}

Vamos a crear un test de prueba para ver como funciona AutoMapper:

[TestMethod]

public void Transform_Invoice_To_InvoiceDto()

{

    var invoiceId = new Guid("C30B6A72-C822-11E0-99CD-3B224824019B");

    var customerId = new Guid("B4228FF2-C824-11E0-844C-6E244824019B");

 

    var invoice = new Invoice

    {

        Id = invoiceId,

        Customer = new Customer

        {

            Id = customerId,

            FirstName = "FirstName",

            LastName = "LastName"

        },

        Lines = new List<InvoiceLine>

        {

            new InvoiceLine

                {

                    Id = Guid.NewGuid(),

                    Product = new Product

                    {

                        Name = "MotherBoard",

                        Price = 120

                    },

                    Quantity = 20

                },

            new InvoiceLine

                {

                    Id = Guid.NewGuid(),

                    Product = new Product

                    {

                        Name = "CPU",

                        Price = 230

                    },

                    Quantity = 10

                }

        }

    };

 

    Mapper.CreateMap<Invoice, InvoiceDto>();

    var invoiceDto = Mapper.Map<Invoice, InvoiceDto>(invoice);

 

    Assert.AreEqual(invoiceDto.Id, invoiceId);

    Assert.AreEqual(invoiceDto.CustomerId, customerId);

    Assert.AreEqual(invoiceDto.Total, invoice.Lines.Sum(l => l.Product.Price * l.Quantity));

}

Vamos a ver que estamos haciendo en el test por pasos:

  1. Creamos una factura de prueba.
  2. Con la función CreateMap de AutoMapper creamos un mapeo entre nuestra entidad de dominio Invoice y el DTO que vamos a enviar al ERP InvoiceDto.
  3. Acto seguido, hacemos uso de la función Map, indicando el tipo de dato de origen y el tipo de dato de destino y pasamos como parámetro nuestra factura de prueba y el se encargará de mapearla automaticamente a nuestro DTO y retornarlo.
  4. Por último, comprobamos que lo ha mapeado correctamente, que los ids coinciden y que el total es el mismo.

¿Donde está la magia?

Pues como dijimos antes, aquí no hay magia, AutoMapper ha usado lo que conocemos como convención frente a configuración, ha mapeado el Id de nuestra factura con el Id del DTO, para el caso del cliente ha usado la convención Clase.Propiedad (CustomerId –> Customer.Id) y para el Total ha buscado un método que se llame GetTotal.

Para el total también aplicaría si usasemos una propiedad tal que así:

public decimal Total

{

    get { return Lines.Sum(l => l.Product.Price*l.Quantity); }

}

En el siguiente post veremos otro tipo de transformación Projection, donde vamos a configurar la API de AutoMapper para hacer algún mapeo más customizado
 
Hasta la próxima.

Un comentario en “AutoMapper (I) Flattening”

  1. Hola Luis,

    AutoMapper va genial! En el post indicas uno de sus múltiples usos, el paso de objetos de datos a sistemas externos… otro uso que le podemos dar es para crear los ViewModels a partir de entidades del dominio en aplicaciones ASP.NET MVC3.

    En este sentido me sorprendió bastante que no se pudiera hacer el mapeo inverso, es decir, pasar de ViewModel a entidades del dominio (tenéis la justificación de Jimmy Bogart aquí: http://lostechies.com/jimmybogard/2009/09/18/the-case-for-two-way-mapping-in-automapper/)…

    ¿Necesitáis hacer el mapping ViewModel -> entidad del dominio? ¿Cómo lo hacéis? ¿”a manija”?

    Buen post para introducir el flattering y a Automapper!

    Salute!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *