Implementando AutoMapper sin perderte en el camino.

César Delgado
Aug 31, 2018 · 4 min read

¿Qué es AutoMapper?, su nombre de por sí ya resulta intuitivo, es una pequeña librería que nos ayuda a quitarnos un peso de encima, esa parte del código que todos odiamos, como lo es el relacionar los campos de un objeto con otro. Así como cuando relacionamos una entidad de la base de datos con un modelo de nuestra vista.

public class CustomerViewModel
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
public DateTime FechaNacimiento { get; set; }
public bool Activo { get; set; }
}
public class Customer
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
public DateTime FechaNacimiento { get; set; }
public bool Activo { get; set; }
}

Nuestra Fuente de Datos

private IEnumerable GetAllCustomer()
{

List customers = new List
{
new Customer { Nombre = "Cesar",
Apellidos = "Delgado",
FechaNacimiento = new DateTime(1978, 02, 03),
Activo = true },
new Customer { Nombre = "Massiel",
Apellidos = "Suapau",
FechaNacimiento = new DateTime(1985,07,09),
}
};

return customers;
}

Ejemplo de relación manual.

public ActionResult Clientes()
{

var Lstcustomers = from c in GetAllCustomer()
select new CustomerViewModel {
Nombre = c.Nombre,
Apellidos = c.Apellidos,
FechaNacimiento = c.FechaNacimiento
};

return View(Lstcustomers);
}

En una relación como el ejemplo, es muy fácil realizar y mantener la relación manual, y sobre todo no nos toma tiempo hacerla, pero ¿qué sucedería si en vez de cuatro campos y quizás una sola entidad a consultar, tuviéramos que relacionar un número mayor de campos en todas las diferentes consultas que necesitamos para nuestra aplicación?, ¿Qué tiempo nos tomaría hacer esto y asegurarnos de que no exista errores por tipo de datos o campos nulos?

Es en esta circunstancia que entra AutoMapper, y a continuación veremos cómo.

Lo más Básico:

1. Instalar AutoMapper.

Mediante NuGet escribimos el siguiente comando:

PM> Install-Package AutoMapper.

2. Configurando AutoMapper.

Una vez Instalado pasamos a la inicialización y configuración, para esto abrimos el archivo Global.asax y en el método Application_Start() agregamos la siguiente línea:

AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<Customer, CustomerViewModel>());

3. Modificando nuestro código para por fin implementar AutoMapper.

public ActionResult Clientes(){

//var Lstcustomers = from c in GetAllCustomer()
// select new CustomerViewModel {
// Nombre = c.Nombre,
// Apellidos = c.Apellidos,
// FechaNacimiento = c.FechaNacimiento
// };

var Lstcustomers = Mapper.Map<IEnumerable<CustomerViewModel>>(GetAllCustomer());

return View(Lstcustomers);

}

Y que sucede si deseo algo más complejo, algo como un campo calculado o deseo retornar un texto en vez de un campo numérico.

Un poco más complejo.

Intentemos retornar un campo FullName, donde concatenemos el Nombre y el Apellido del Cliente, que muy bien podemos realizar desde nuestro viewmodel, pero intentémoslo con AutoMapper.

Agreguemos la propiedad FullName a nuestro ViewModel, así:

public class CustomerViewModel
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
public string FullName { get; set; }
public DateTime FechaNacimiento { get; set; }
public bool Activo { get; set; }
}

Ahora digámosle a AutoMapper como llenar esta propiedad, modifiquemos la inicialización que colocamos en el método Application_Start() del Global.asax agregando la siguiente línea y listo.

AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<Customer, CustomerViewModel>()
.ForMember(cv => cv.FullName,
c => c.MapFrom(s => $"{s.Nombre} {s.Apellidos}"))
);

Y si se me ocurre agregar información que está contenida dentro de otra entidad? Algo así asociar la empresa a la cual pertenece.

public class Empresa
{
public string Nombre { get; set; }
}

Modifiquemos nuestra entidad Customer para que admita empresa y nuestro viewModel para que muestre la empresa

public class Customer
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
public DateTime FechaNacimiento { get; set; }
public Empresa Empresa { get; set; }
public bool Activo { get; set; }

}

public class CustomerViewModel
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
public string FullName { get; set; }
public DateTime FechaNacimiento { get; set; }
public string EmpresaNombre { get; set; }
public bool Activo { get; set; }
}

Al igual que como hicimos con la propiedad FullName, modificamos nuestro inicialización y agregamos la siguiente línea.

AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<Customer, CustomerViewModel>()
.ForMember(cv => cv.FullName,
c => c.MapFrom(s => $"{s.Nombre} {s.Apellidos}"))
.ForMember(cv => cv.EmpresaNombre,
c => c.MapFrom(s => s.Empresa.Nombre))
);

Si se fijan he cambiado el nombre de la propiedad empresa dentro del CustomerViewModel y lo he asociado sin problemas dentro de la configuración.

Ya por último imaginen que quiero que el campo Activo en vez de salir True o False, me devuelva Si o No, para esto vamos a cambiar el tipo de datos de nuestra propiedad Activo dentro del ViewModel de boolean a String, y luego agrega algo más de complejidad.

public class CustomerViewModel
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
public string FullName { get; set; }
public DateTime FechaNacimiento { get; set; }
public string EmpresaNombre { get; set; }
public string Activo { get; set; }
}

Ahora agreguemos una nueva clase la cual va a implementar la interfaz IValueResolver.

public class ActivoResolver : IValueResolver<Customer, CustomerViewModel, string>
{
public string Resolve(Customer customer,
CustomerViewModel customerViewModel,
string destMember,
ResolutionContext context)
{
return (customer.Activo) ? "Si" : "No";
}
}

Y por último modifiquemos nuevamente la inicialización de AutoMapper, como se muestra a continuación:

AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<Customer, CustomerViewModel>()
.ForMember(cv => cv.FullName,
c => c.MapFrom(s => $"{s.Nombre} {s.Apellidos}"))
.ForMember(cv => cv.EmpresaNombre,
c => c.MapFrom(s => s.Empresa.Nombre))
.ForMember(cv => cv.Activo,
opt => opt.ResolveUsing<ActivoResolver>())
);

Espero no haberlos confundido más.

Si deseas abundar un poco más, te invito a continuar leyendo su documentación aquí.


Sígueme en Linkedin.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade