jk's notes
  • 继承映射

继承映射

集成映射有两个功能:

  • 从基类或配置接口集成映射配置.
  • 运行多态映射

继承基类配置是可选的, 你可以使用 Include 显式的指定映射来继承基类配置, 或者在派生类中通过 IncludeBase 来配置:

CreateMap<BaseEntity, BaseDto>()
  .Include<DerivedEntity, DerivedDto>()
  .ForMember(dest => dest.SomeMember, opt => opt.MapFrom(src => src.OtherMember));
CreateMap<DerivedEntity, DerivedDto>();

或者

CreateMap<BaseEntity, BaseDto>()
  .ForMember(dest => dest.xxx, opt => opt.MapFrom(src => src.xxx));
CreateMap<DerivedEntity, DerivedDto>()
  .IncludeBase<BaseEntity, BaseDto>();

上面的两段代码都可以在派生映射中继承基映射的配置.

Include / IncludeBase 具有递归的特性, 因此只需要配置继承结构上最近的两个类型即可.

如果需要作用所有的派生类, 可以使用 IncludeAllDerived() 方法. 但需要注意性能问题. 这样会扫描所有派生类.

CreateMap<BaseENtity, BaseDto>()
  .IncludeAllDerived();
CreateMap<DerivedEntity, DerivedDto>();

运行时多态

存在多个派生类, 同时又配置了多个派生类的映射时, 可以在 Map 的时候指定被目标类型.

public class Order { }
public class OnlineOrder : Order { }
public class MailOrder : Order { }

public class OrderDto { }
public class OnlineOrderDto : OrderDto { }
public class MailOrderDto : OrderDto { }

var configuration = new MapperConfiguration(cfg => {
  cfg.CreateMap<Order, OrderDto>()
    .Include<OnlineOrder, OnlineOrderDto>()
    .Include<MailOrder, MailOrderDto>();
  cfg.CreateMap<OnlineOrder, OnlineOrderDto>();
  cfg.CreateMap<MailOrder, MailOrderDto>();
});

// Perform Mapping
var order = new OnlineOrder();
var mapped = mapper.Map(order, order.GetType(), typeof(OrderDto));
Assert.IsType<OnlineOrderDto>(mapped);

上述代码使用了 Map 的重载

image-20240102144447573

在派生类中指定继承 (待验证)

绕过从基类集成, 在子类中指定集成

var configuration = new MapperConfiguration(cfg => {
  cfg.CreateMap<Order, OrderDto>()
    .ForMember(o => o.Id, m => m.MapFrom(s => s.OrderId));
  cfg.CreateMap<OnlineOrder, OnlineOrderDto>()
    .IncludeBase<Order, OrderDto>();
  cfg.CreateMap<MailOrder, MailOrderDto>()
    .IncludeBase<Order, OrderDto>();
});

案例只有两层集成关系, 有待验证在三层, 四层或更多层集成关系中, 是否可以从中间指定.

As

简单情况下, 可以使用 As 将基映射从定向导已存在的派生映射上

cfg.CreateMap<Order, OnlineOrderDto>();
cfg.CreateMap<Order, OrderDto>().As<OnlineOrderDto>();

mapper.Map<OrderDto>(new Order()).ShouldBeOfType<OnlineOrderDto>();

继承映射的优先级

这部分主题较复杂, 因为可以映射属性的方式有很多. 决定优先级的顺序为:

  • 显式映射 (使用 .MapFrom())
  • 显式继承映射
  • 忽略属性映射
  • 默认约定映射 (通过约定来匹配属性)

jk: 文档比较生硬, 而且逻辑层次不清. 常常会在很多主题中混入其他主题的内容. 对于初学使用者并不友好. 还是应该再整理一篇. 2024年1月2日

Last Updated:
Contributors: jk