使用Automapper将大型模型映射到数据库对象

使用Automapper将大型模型映射到数据库对象

问题描述:

我想使用Automapper将我的模型对象映射到数据库对象。假设数据库对象超过30个字段,我想从我的模型中映射20个属性中的10个。为了使它更复杂,我需要在更新记录时映射不同的属性,而不是将新记录插入数据库。使用Automapper将大型模型映射到数据库对象

我正在使用的解决方案是创建2个泛型类插入和更新和映射配置文件,指定两个映射。

下面的例子:

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) 
    { 
    } 
} 

的映射,但是,越来越讨厌的圈复杂度在天上去(50),因为我需要定义忽略()为所有属性我不图:

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()); 

我已经解决了这个问题通过创建新的对象插入新记录:

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()); 

但是,在我要地图的属性到现有的对象,而不是新的实例不更新工作:

 Mapper.Map(update, existingRecord); 

我宁愿避免DynamicMap(),以保持完全控制的映射(所以我会不要错误地映射一个随机属性)。我的目标是解决圈复杂性问题。请不要建议ValueInjecter或任何其他方法。我在AutoMapper中寻找解决方案。

+0

你有没有找到解决的办法?我在同一个任务:/ – 2014-12-23 21:29:09

+0

不,我简化了我的模型。但是,我相信ThiagoSá的答案应该适用于当前版本的AutoMapper。 – 2015-08-28 09:18:45

这是五年后,但这里有一个建议,以减少这种映射复杂性问题。您可以创建一个扩展,将帮助您忽略所有成员第一:

public static class AutoMapperExtension { 
    public static IMappingExpression<TSource, TDest> IgnoreAllMembers<TSource, TDest>(this IMappingExpression<TSource, TDest> expression) { 
     expression.ForAllMembers(opt => opt.Ignore()); 
     return expression; 
    } 
} 

然后你用它来定义仅要执行的映射:

Mapper.CreateMap<Insert<OracleModel>, LiveModel>() 
     .IgnoreAllMembers() 
     .ForMember(d => d.BaseUnit, o => o.MapFrom(s => s.Model.UOM.BaseUOM.PerSalesUnit)) 
     /* Mapping for other members here. */;