Mapeo de modelos
Visión general
El mapeo automático de objetos es útil cuando necesitas convertir de un tipo A a un tipo B (por ejemplo, de una entidad Prestamo a un modelo de vista PrestamoModelo, o al revés) sin asignar cada propiedad a mano. Crono incluye utilidades de mapeo muy ligeras y rápidas, en Crono.ComponenteModelo:
| Utilidad | Descripción | Llamada |
|---|---|---|
MapeadorMini | Mapeador de objetos muy simple. | MapeadorMini.Mapear(origen, destino) |
MapeadorFabrica | Mapeador avanzado, personalizable y flexible. | MapeadorFabrica.MapearAsync(origen, destino) |
MapeadorMini
MapeadorMini intenta mapear propiedades con el mismo nombre entre dos objetos, usando reflexión. Si las propiedades coinciden en nombre pero difieren en tipo, intenta convertirlas con el sistema de conversión de tipos; si no lo logra, simplemente omite la propiedad (no lanza excepción).
Úsalo cuando:
- El tipo origen y destino se parecen bastante.
- No necesitas control total sobre el mapeo.
Limitaciones: no copia en profundidad colecciones ni clona tipos por referencia.
// Mapea Configuraciones --> ConfiguracionModelo (el destino debe tener
// un constructor sin parámetros) y devuelve la instancia destino
var modelo = MapeadorMini.Mapear<MiConfiguraciones, ConfiguracionModelo>(configuraciones);
// Mapea sobre una instancia destino ya existente
var modelo = new ConfiguracionModelo();
MapeadorMini.Mapear(configuraciones, modelo);
MapeadorFabrica
MapeadorFabrica es una fábrica estática que crea instancias de mapeadores personalizados (IMapeador<TDe, TA>).
Úsalo cuando:
- El tipo origen y destino son muy diferentes.
- Necesitas más control sobre el mapeo.
Al iniciarse, MapeadorFabrica detecta automáticamente todas las clases concretas IMapeador<TDe, TA> de los ensamblados cargados. Como está habilitado para inyección de dependencias, un mapeador puede depender de cualquier servicio registrado. Si no encuentra un mapeador para un par de tipos, usa uno genérico que delega internamente en MapeadorMini.
Implementar un mapeador
Crea una clase que implemente IMapeador<TDe, TA>. Una misma clase puede implementar varias direcciones (por ejemplo IMapeador<Prestamo, PrestamoModelo> e IMapeador<PrestamoModelo, Prestamo>). No hace falta registrarla en la inyección de dependencias. Es buena práctica mantener el modelo y su mapeador en el mismo archivo.
public class PrestamoMapeador :
IMapeador<Prestamo, PrestamoModelo>,
IMapeador<PrestamoModelo, Prestamo>
{
public Task MapearAsync(Prestamo de, PrestamoModelo a, dynamic parametros = null)
{
// ... mapear Prestamo --> PrestamoModelo ...
return Task.CompletedTask;
}
public Task MapearAsync(PrestamoModelo de, Prestamo a, dynamic parametros = null)
{
// ... mapear PrestamoModelo --> Prestamo ...
return Task.CompletedTask;
}
}
Distintas formas de mapear una entidad a un modelo:
Prestamo entidad = /* obtener la entidad */;
var modelo = new PrestamoModelo();
// Obtener el mapeador (una instancia de "PrestamoMapeador")
var mapeador = MapeadorFabrica.ObtenerMapeador<Prestamo, PrestamoModelo>();
await mapeador.MapearAsync(entidad, modelo);
// - o de forma directa, sin resolver el mapeador primero -
await MapeadorFabrica.MapearAsync(entidad, modelo);
// - con parámetros -
await mapeador.MapearAsync(entidad, modelo, new { Opcion1 = true, Opcion2 = "algo" });
El mapeo es la base de muchas utilidades del framework: por ejemplo, los atributos CargarConfiguracion / GuardarConfiguracion (ver Configuración) copian valores entre la configuración y su modelo mediante estos mapeadores.