简体   繁体   English

Automapper:如何不重复从复杂类型到基类的映射配置

[英]Automapper: How to not repeat mapping config from complex type to base class

I have a bunch of DTO classes that inherit from this CardBase : 我有一堆从此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 ...
}

In my MVC project I have a bunch of view models with a AuditVm complex type that has the same properties of CardBase : 在我的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 }
}

Those view models cannot inherit from AuditVm because each of them already has a parent. 这些视图模型不能从AuditVm继承,因为它们每个都已经有一个父视图。 I thought I could setup my mapping like below so I would not have to specify the map from AuditVm to the CardBase for every view model that has AuditVm as a complex type. 我以为可以像下面那样设置映射,因此CardBase为每个将AuditVm作为复杂类型的视图模型指定从AuditVmCardBase的映射。 But it is not working. 但这是行不通的。 How do I properly map from a complex type to a flatten type with properties on the base class? 如何正确地将复杂类型映射到具有基类属性的扁平类型?

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

UPDATE: here is the fiddle https://dotnetfiddle.net/iccpE0 更新:这是小提琴https://dotnetfiddle.net/iccpE0

.Include is for a very specific case--you have two identically-structured class hierarchies you'd like to map, for example: .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.

So unless you have this kind of situation, .Include isn't the right thing to use. 因此,除非您遇到这种情况, .Include不是正确的选择。

I think your best bet is to use ConstructUsing : 我认为您最好的选择是使用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();

I've also incorporated this answer's extension method to ignore all unmapped properties. 我还结合了此答案的扩展方法,以忽略所有未映射的属性。 Since we're using ConstructUsing , AutoMapper doesn't know that we've already taken care of those properties. 由于我们使用的是ConstructUsing ,因此AutoMapper不知道我们已经处理了这些属性。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM