自动映射器:如何不重复将配置从复杂类型映射到基类

本文关键字:映射 配置 复杂 基类 类型 何不重 | 更新日期: 2023-09-27 18:33:13

我有一堆从这个CardBase继承的DTO类:

// base class
public class CardBase
{
  public int TransId {get; set; }
  public string UserId  { get; set; }
  public int Shift { get; set; }
}
// one of the concrete classes
public class SetNewCardSettings : CardBase
{
  // specific properties ...
}

在我的 MVC 项目中,我有一堆具有AuditVm复杂类型的视图模型,具有相同的 CardBase 属性:

public class AuditVm
{
  public int TransId {get; set; }
  public string UserId  { get; set; }
  public int Shift { get; set; }
}
public class CreateCardVm : CardVm
{
  // specific properties here ...
  public AuditVm Audit { get; set }
}

这些视图模型不能从AuditVm继承,因为它们中的每一个都已经有一个父模型。我想我可以像下面这样设置我的映射,这样我就不必为每个AuditVm为复杂类型的视图模型指定从AuditVmCardBase的映射。但它不起作用。如何从复杂类型正确映射到基类上具有属性的平展类型?

  Mapper.CreateMap<AuditorVm, CardBase>()
    .Include<AuditorVm, SetNewCardSettings>();
  // this does not work because it ignores my properties that I map in the second mapping
  // if I delete the ignore it says my config is not valid
  Mapper.CreateMap<AuditorVm, SetNewCardSettings>()
    .ForMember(dest => dest.Temp, opt => opt.Ignore())
    .ForMember(dest => dest.Time, opt => opt.Ignore());
  Mapper.CreateMap<CreateCardVm, SetNewCardSettings>()
     // this gives me an error
    .ForMember(dest => dest, opt => opt.MapFrom(src => Mapper.Map<AuditorVm, SetNewCardSettings>(src.Auditor)));
    // I also tried this and it works, but it does not map my specific properties on SetNewCardSettings
    //.ConvertUsing(dest => Mapper.Map<AuditorVm, SetNewCardSettings>(dest.Auditor));

更新:这是小提琴 https://dotnetfiddle.net/iccpE0

自动映射器:如何不重复将配置从复杂类型映射到基类

.Include适用于非常特殊的情况 - 您有两个结构相同的类层次结构想要映射,例如:

public class AEntity : Entity { }
public class BEntity : Entity { }
public class AViewModel : ViewModel { }
public class BViewModel : ViewModel { }
Mapper.CreateMap<Entity, ViewModel>()
    .Include<AEntity, AViewModel>()
    .Include<BEntity, BViewModel>();
// Then map AEntity and BEntity as well.

因此,除非您遇到这种情况,否则.Include不是正确的使用方法。

我认为你最好的选择是使用ConstructUsing

 Mapper.CreateMap<AuditVm, CardBase>();
 Mapper.CreateMap<AuditVm, SetNewCardSettings>()
     .ConstructUsing(src => 
          {
              SetNewCardSettings settings = new SetNewCardSettings();
              Mapper.Map<AuditVm, CardBase>(src, settings);
              return settings;
          })
     .IgnoreUnmappedProperties();
 Mapper.CreateMap<CreateCardVm, SetNewCardSettings>()
     .ConstructUsing(src => Mapper.Map<SetNewCardSettings>(src.Audit))
     .IgnoreUnmappedProperties();

我还合并了此答案的扩展方法以忽略所有未映射的属性。由于我们使用的是ConstructUsing,AutoMapper不知道我们已经处理了这些属性。

更新的小提琴:https://dotnetfiddle.net/6ZfZ3z