AutoMapper - 根据条件映射到派生对象

3
我希望将源类根据某个属性的值映射到派生类(从抽象类派生)中。
我有以下源类:
public partial class ApplicationDriver
{
    public virtual ICollection<ApplicationDriverEquipment> Equipments { get; set; }

}

public partial class ApplicationDriverEquipment
{
    public int Id { get; set; }
    [StringLength(256)]
    public string Make { get; set; }
    [StringLength(256)]
    public string Model { get; set; }
    [StringLength(256)]
    public string Year { get; set; }
    [StringLength(256)]
    public string VINNumber { get; set; }
    [StringLength(256)]
    public string PlateNumber { get; set; }
    [StringLength(256)]
    public string CurrentMileage { get; set; }
    [StringLength(256)]
    public string Length { get; set; }
    public string Type { get; set; }

    public int DriverId { get; set; }
    public virtual ApplicationDriver Driver { get; set; }
}

我希望根据Type参数映射到以下类:

public class ApplicationDriverDomain
{
    public List<ApplicationDriverEquipmentAbstractDomain> Equipments { get; set; }

}

public abstract class ApplicationDriverEquipmentAbstractDomain
{
    public int Id { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
    public string Year { get; set; }
    public string PlateNumber { get; set; }
    public string CurrentMileage { get; set; }
    public string Type { get; protected set; }
}

public class ApplicationDriverEquipmentTractorDomain : ApplicationDriverEquipmentAbstractDomain
{
    public ApplicationDriverEquipmentTractorDomain()
    {
        Type = ApplicationDriverEquipmentTypeStaticStringsDomain.Tractor;
    }
    public string VINNumber { get; set; }
}

public class ApplicationDriverEquipmentTrailerDomain : ApplicationDriverEquipmentAbstractDomain
{
    public ApplicationDriverEquipmentTrailerDomain()
    {
        Type = ApplicationDriverEquipmentTypeStaticStringsDomain.Trailer;
    }

    public string Length { get; set; }
}

public class ApplicationDriverEquipmentStraightTruckDomain : ApplicationDriverEquipmentAbstractDomain
{
    public ApplicationDriverEquipmentStraightTruckDomain()
    {
        Type = ApplicationDriverEquipmentTypeStaticStringsDomain.StraightTruck;
    }

    public string VINNumber { get; set; }
    public string Length { get; set; }
}

public class ApplicationDriverEquipmentCargoVanDomain : ApplicationDriverEquipmentAbstractDomain
{
    public ApplicationDriverEquipmentCargoVanDomain()
    {
        Type = ApplicationDriverEquipmentTypeStaticStringsDomain.CargoVan;
    }

    public string VINNumber { get; set; }
    public string Length { get; set; }
}

我会尝试做到这一点:
    ApplicationDriverEquipmentAbstractDomain GetEquipment(Infrastructure.Asset.ApplicationDriverEquipment infrastructure)
    {
        ApplicationDriverEquipmentAbstractDomain result = null;
        var config = new MapperConfiguration(cfg => cfg.AddProfile<AutoMapperApplicationModel>());
        var mapper = config.CreateMapper();

        switch (infrastructure.Type)
        {
            case ApplicationDriverEquipmentTypeStaticStringsDomain.Tractor:
                result = mapper.Map<ApplicationDriverEquipmentTractorDomain>(infrastructure);
                break;

            case ApplicationDriverEquipmentTypeStaticStringsDomain.Trailer:
                result = mapper.Map<ApplicationDriverEquipmentTrailerDomain>(infrastructure);
                break;

            case ApplicationDriverEquipmentTypeStaticStringsDomain.StraightTruck:
                result = mapper.Map<ApplicationDriverEquipmentStraightTruckDomain>(infrastructure);
                break;

            case ApplicationDriverEquipmentTypeStaticStringsDomain.CargoVan:
                result = mapper.Map<ApplicationDriverEquipmentCargoVanDomain>(infrastructure);
                break;

        }

        return result;
    }

        CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentTractorDomain>();
        CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentTrailerDomain>();
        CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentStraightTruckDomain>();
        CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentCargoVanDomain>();

        CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentAbstractDomain>()
            .Include<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentTractorDomain>()
            .Include<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentTrailerDomain>()
            .Include<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentStraightTruckDomain>()
            .Include<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentCargoVanDomain>()
            .ForMember(dest => dest.Type, opt => opt.ResolveUsing(GetEquipment))
            ;

        CreateMap<Infrastructure.Asset.ApplicationDriver, ApplicationDriverDomain>()
            .ForMember(dest => dest.Equipments, opt => opt.MapFrom(src => src.Equipments));

但是我遇到了一个错误:

"映射类型出错。\r\n\r\n映射的类型:\r\nApplicationDriver -> ApplicationDriverDomain\r\nInfrastructure.Asset.ApplicationDriver -> Domain.POCO.Application.ApplicationDriverDomain\r\n\r\n类型映射配置:\r\nApplicationDriver -> ApplicationDriverDomain\r\nInfrastructure.Asset.ApplicationDriver -> Domain.POCO.Application.ApplicationDriverDomain\r\n\r\n属性:\r\nEquipments"


什么是AutoMapperApplicationModel?你能发布这段代码吗?请告诉我们AutoMapper的版本。 - Rex
但我发布了Automapper的代码。Automapper的版本是6.1.1。 - Oleg Sh
https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance - Lucian Bargaoanu
@LucianBargaoanu 我没有找到答案。 - Oleg Sh
请查看此帖子,它看起来很相似:https://dev59.com/e2bWa4cB1Zd3GeqPb-6H#46394030 - ASpirin
2个回答

2

更新:

我相信我理解了你想要做的事情,如果我稍微让你走了些弯路,我很抱歉。你的流程基本上是区分源对象的基础设施类型,然后创建该类型的对象。此外,你需要了解两种不同的 Mapper 设置方式。

在代码的第一部分中,你试图使用 Mapper 的实例来设置它,但是使用我的静态样式 Mapper.Map。我建议始终使用静态样式,这样你就可以使用一些更动态的方法来提取映射配置文件。

Mapper.Initialize(cfg => cfg.AddProfile<AutomapperRules>());
var domain = Mapper.Map<Domain.ApplicationDriverEquipmentTractorDomain>(inf);

接下来,您只需要引用从底层源到您个人资料中的域类型的映射类型即可。

CreateMap<ApplicationDriverEquipmentInfrastructure, ApplicationDriverEquipmentTractorDomain>();
CreateMap<ApplicationDriverEquipmentInfrastructure, ApplicationDriverEquipmentTrailerDomain>();
CreateMap<ApplicationDriverEquipmentInfrastructure, ApplicationDriverEquipmentStraightTruckDomain>();
CreateMap<ApplicationDriverEquipmentInfrastructure, ApplicationDriverEquipmentCargoVanDomain>();

那么你需要做的就是从描述ApplicationDriver的映射中调用你的GetEquipment方法。

CreateMap<ApplicationDriver, ApplicationDriverDomain>()
            .ForMember(dest => dest.Equipments, opt => opt.ResolveUsing(x => x.Equipments.Select(GetEquipment)));

private ApplicationDriverEquipmentAbstractDomain GetEquipment(ApplicationDriverEquipmentInfrastructure infrastructure)
    {
        switch (infrastructure.Type)
        {
            case "Tractor":
                return Mapper.Map<ApplicationDriverEquipmentTractorDomain>(infrastructure);
            case "Trailer":
                return Mapper.Map<ApplicationDriverEquipmentTrailerDomain>(infrastructure);
            case "StraightTruck":
                return Mapper.Map<ApplicationDriverEquipmentStraightTruckDomain>(infrastructure);
            case "CargoVan":
                return Mapper.Map<ApplicationDriverEquipmentCargoVanDomain>(infrastructure);
        }
        return null;
    }

示例用法:

Mapper.Initialize(cfg => cfg.AddProfile<AutomapperRules>());

var inf = new ApplicationDriverEquipmentInfrastructure()
{
     CurrentMileage = "mil",
     Length = "123",
     Make = "ccc",
     Model = "15",
     Type = "Tractor",
     VINNumber = "vin"
};

var driver = new ApplicationDriver()
{
     Equipments = new List<ApplicationDriverEquipmentInfrastructure>() {inf}
};

var domain = Mapper.Map<ApplicationDriverDomain>(driver);

NullReferenceException: 对象引用未设置为对象的实例。 具有相同的内部错误。 - Oleg Sh
你能否提供更多信息或者一个 Github 仓库的参考,因为这可能与你的设置有关。 - codeplay

0

AM中的继承是通过检查源类型而不是使用鉴别器来实现的。这就是你应该从文档中理解的内容。解决问题的一种方法是将现有目标传递给Map。可以通过类似于你那里的GetEquipment方法创建。ApplyBaseMapping是一个hack,你可以使用Include/IncludeBase来重用配置。不幸的是,你也遇到了一个已经在MyGet版本中修复的错误,所以真正的错误有点被隐藏了。在你的版本中调试这个问题的唯一方法是检查执行计划


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接