Usa Automapper per mappare modelli di dominio grandi di oggetti di database
-
02-10-2019 - |
Domanda
Vorrei utilizzare Automapper per mappare i miei oggetti del modello a oggetti di database. Lasciate oggetto di database per esempio è di oltre 30 campi e voglio mappa 10 su 20 oggetti di mio modello. Per realizzarlo ho bisogno più complesso per mappare diverse proprietà quando aggiorno registrazione rispetto a quando inserisco nuovo record al database.
La soluzione che sto utilizzando è quello di creare 2 classi generiche di inserimento e aggiornamento e di profilo di mappatura che specifica sia mappature.
L'esempio che segue:
public abstract class SyncMappingWrapper<TFrom> where TFrom : class
{
protected SyncMappingWrapper(TFrom model)
{
Model = model;
}
public TFrom Model { get; private set; }
}
public class Update<TFrom> : SyncMappingWrapper<TFrom> where TFrom : class
{
public Update(TFrom model)
: base(model)
{
}
}
public class Insert<TFrom> : SyncMappingWrapper<TFrom> where TFrom : class
{
public Insert(TFrom model)
: base(model)
{
}
}
La mappatura, tuttavia, è sempre brutto come la complessità ciclomatica va in al cielo (oltre 50), come ho bisogno di definire Ignora () per tutte le proprietà che non Map:
CreateMap<Update<OracleModel>, LiveModel>()
.ForMember(des => des.ApprovedBy, opt => opt.Ignore())
.ForMember(des => des.ApprovedDate, opt => opt.Ignore())
...
.ForMember(des => des.UNSPSC, opt => opt.Ignore())
.ForMember(des => des.BaseUnit, opt => opt.MapFrom(src => src.Model.UOM.BaseUOM.PerSalesUnit))
.ForMember(des => des.BaseUOM, opt => opt.MapFrom(src => src.Model.UOM.BaseUOM.UnitOfMeasure.Code))
.ForMember(des => des.SalesUnit, opt => opt.MapFrom(src => src.Model.UOM.SalesUOM.PerSalesUnit))
.ForMember(des => des.SalesUOM, opt => opt.MapFrom(src => src.Model.UOM.SalesUOM.UnitOfMeasure.Code))
.ForMember(des => des.OrderUnit, opt => opt.MapFrom(src => src.Model.UOM.OrderUOM.PerSalesUnit))
.ForMember(des => des.OrderUOM, opt => opt.MapFrom(src => src.Model.UOM.OrderUOM.UnitOfMeasure.Code))
.ForMember(des => des.SalesPrice, opt => opt.MapFrom(src => src.Model.Price.Value))
.ForMember(des => des.Alternate, opt => opt.Ignore())
.ForMember(des => des.ManufacturerID, opt => opt.Ignore())
.ForMember(des => des.ProductCode, opt => opt.MapFrom(src => src.Model.ProductCode))
.ForMember(des => des.ProductName, opt => opt.MapFrom(src => src.Model.ProductName))
.ForMember(des => des.ProductHTML, opt => opt.Ignore())
.ForMember(des => des.Version, opt => opt.Ignore())
...
.ForMember(des => des.UnitsOfMeasure2, opt => opt.Ignore())
.ForMember(des => des.Manufacturer, opt => opt.Ignore());
Ho risolto il problema per l'inserimento di nuovo record con la creazione di nuovo oggetto:
CreateMap<Insert<OracleModel>, LiveModel>()
.ConstructUsing(x => new LiveModel
{
BaseUnit = x.Model.UOM.BaseUOM.PerSalesUnit,
BaseUOM = x.Model.UOM.BaseUOM.UnitOfMeasure.Code,
SalesUnit = x.Model.UOM.SalesUOM.PerSalesUnit,
SalesUOM = x.Model.UOM.SalesUOM.UnitOfMeasure.Code,
OrderUnit = x.Model.UOM.OrderUOM.PerSalesUnit,
OrderUOM = x.Model.UOM.OrderUOM.UnitOfMeasure.Code,
SalesPrice = x.Model.Price.Value,
LeadTime = x.Model.LeadTime,
ProductCode = x.Model.ProductCode,
ProductName = x.Model.ProductName,
SupplierCode = x.Model.SupplierCode,
Weight = x.Model.Weight
})
.ForAllMembers(xc => xc.Ignore());
Ma non funziona per gli aggiornamenti dove voglio mappare le proprietà a un oggetto esistente e non nuova istanza:
Mapper.Map(update, existingRecord);
preferirei evitare di DynamicMap () per mantenere il pieno controllo della mappatura (quindi non mi mappare una proprietà a caso per errore). Il mio obiettivo è quello di risolvere ciclomatica complessità del problema. Si prega di non suggerire ValueInjecter o altri metodi. Sto cercando una soluzione entro automapper.
Soluzione
E 'cinque anni più tardi, ma ecco un suggerimento per ridurre questo problema mappatura complessità. È possibile creare un'estensione che vi aiuterà a ignorare tutti i membri in un primo momento:
public static class AutoMapperExtension {
public static IMappingExpression<TSource, TDest> IgnoreAllMembers<TSource, TDest>(this IMappingExpression<TSource, TDest> expression) {
expression.ForAllMembers(opt => opt.Ignore());
return expression;
}
}
Poi lo si utilizza per definire solo le mappature che si desidera eseguire:
Mapper.CreateMap<Insert<OracleModel>, LiveModel>()
.IgnoreAllMembers()
.ForMember(d => d.BaseUnit, o => o.MapFrom(s => s.Model.UOM.BaseUOM.PerSalesUnit))
/* Mapping for other members here. */;