2014-12-05 69 views
2

我有一大堆的DTO类,从这个CardBase继承:Automapper:如何不从复杂类型重复映射配置基类

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

UPDATE: 这里是小提琴https://dotnetfiddle.net/iccpE0

+0

可您提供的类型,你会映射到从'CreateCardVm',这样你就不得不'Audit'映射到类型CardBase'的'属性的一个例子。 – 2014-12-05 14:21:28

+0

哦,对不起,我复制了上次映射时出现了错误的类。最后一个映射是从'CreateCardVm'(具有'AuditVm')到'SetNewCardSettings'(具有'CardBase') – 2014-12-05 14:34:32

+0

如果'CreateCardVM'没有从'AuditorVM'继承,最后一行(使用'ConvertUsing'的行) '? – 2014-12-05 14:40:25

回答

2

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

我还加入this answer's扩展方法忽略所有未映射属性。由于我们使用的是ConstructUsing,AutoMapper并不知道我们已经处理了这些属性。

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

+0

它的工作!你刚刚救了我一堆时间,谢谢! – 2014-12-05 20:35:45

+0

你知道为什么'CreateCardVm'的属性直接到'SetNewCardSetting'的另一个复杂属性没有映射吗?我更新了小提琴https://dotnetfiddle.net/jU7gto。添加的类是'Foo',属性是'Bar',我添加了一个'CreateMap'。这是我必须明确映射或更改属性名称为'FooBar'按照惯例映射 – 2014-12-08 02:15:03

+0

您可以创建从'Foo'到'string'的映射并使用它,或者使用'MapFrom(src => src .Foo == null?null:Foo.Bar)'。这里有一个更新的小提琴:https://dotnetfiddle.net/jOVaWl – 2014-12-08 13:56:52

相关问题