Automapper 将 2 类 配置为 1

Automapper configure 2 classes to one

我有以下数据库(基础设施)类:

[Table("ApplicationDriverEquipments")]
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 int TypeId { get; set; }
    public virtual ApplicationDriverEquipmentType Type { get; set; }

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

[Table("ApplicationDriverEquipmentTypes")]
public partial class ApplicationDriverEquipmentType
{
    public ApplicationDriverEquipmentType()
    {
        Equipments = new HashSet<ApplicationDriverEquipment>();
    }

    public int Id { get; set; }
    [Required]
    [StringLength(256)]
    public string Name { get; set; }
    public virtual ICollection<ApplicationDriverEquipment> Equipments { get; set; }
}

和以下 DTO(域)类:

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

public static class ApplicationDriverEquipmentTypeStaticStringsDomain
{
    public const string Tractor = "Tractor";
    public const string Trailer = "Trailer";
    public const string StraightTruck = "Straight Truck";
    public const string CargoVan = "Cargo Van";
}

我写了下面的Automapper规则来解决它:

        CreateMap<Domain.POCO.Application.ApplicationDriverEquipmentTractorDomain, Infrastructure.Asset.ApplicationDriverEquipment>()
            .ForMember(c => c.Type.Name, p => p.UseValue<string>(Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.Tractor));
        CreateMap<Domain.POCO.Application.ApplicationDriverEquipmentTrailerDomain, Infrastructure.Asset.ApplicationDriverEquipment>()
            .ForMember(c => c.Type.Name, p => p.UseValue<string>(Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.Trailer));
        CreateMap<Domain.POCO.Application.ApplicationDriverEquipmentStraightTruckDomain, Infrastructure.Asset.ApplicationDriverEquipment>()
            .ForMember(c => c.Type.Name, p => p.UseValue<string>(Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.StraightTruck));
        CreateMap<Domain.POCO.Application.ApplicationDriverEquipmentCargoVanDomain, Infrastructure.Asset.ApplicationDriverEquipment>()
            .ForMember(c => c.Type.Name, p => p.UseValue<string>(Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.CargoVan));

我收到一个错误:

Expression 'c => c.Type.Name' must resolve to top-level member and not any child object's properties. Use a custom resolver on the child type or the AfterMap option instead.

更新

我重写了地图:

        CreateMap<Domain.POCO.Application.ApplicationDriverEquipmentTractorDomain, Infrastructure.Asset.ApplicationDriverEquipment>()
            .AfterMap((src, dest)=> dest.Type.Name = Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.Tractor);
        CreateMap<Domain.POCO.Application.ApplicationDriverEquipmentTrailerDomain, Infrastructure.Asset.ApplicationDriverEquipment>()
            .AfterMap((src, dest) => dest.Type.Name = Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.Trailer);
        CreateMap<Domain.POCO.Application.ApplicationDriverEquipmentStraightTruckDomain, Infrastructure.Asset.ApplicationDriverEquipment>()
            .AfterMap((src, dest) => dest.Type.Name = Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.StraightTruck);
        CreateMap<Domain.POCO.Application.ApplicationDriverEquipmentCargoVanDomain, Infrastructure.Asset.ApplicationDriverEquipment>()
            .AfterMap((src, dest) => dest.Type.Name = Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.CargoVan);

但现在我得到一个错误:

Type Map configuration: ApplicationDriverEquipmentTractorDomain -> ApplicationDriverEquipment Domain.POCO.Application.ApplicationDriverEquipmentTractorDomain -> Infrastructure.Asset.ApplicationDriverEquipment

Property: Type ---> AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.

Mapping types:

String -> ApplicationDriverEquipmentType

System.String -> Infrastructure.Asset.ApplicationDriverEquipmentType

好像,我没看懂怎么正确映射

尝试使用 MapFrom 方法:

.ForMember(c => c.Type.Name, p => p.MapFrom(s => Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.Tractor));

您正在尝试映射自
ApplicationDriverEquipmentTractorDomain.Type 是一个 string

ApplicationDriverEquipment.Type 是一个 ApplicationDriverEquipmentType

你的映射配置在哪里?

甚至可以将字符串映射到 ApplicationDriverEquipmentType 吗?
当然,你可以有一个 string Name,但是你从哪里得到 IdEquipments

我怀疑您不想在每次映射时都创建该类型的新实例,而是您需要从某个字典中查找实例,类似于 registry pattern

要实现这个想法,您只需要

  1. 从 DB
  2. 加载所有 ApplicationDriverEquipmentType
  3. 将它们放入字典中(假设名称是唯一的)
  4. 注册一个custom type converter or custom value resolver如下

实现这一点的一种方法是使用 custom type converter
你可以使用像
这样的东西 void ConvertUsing(Func<TSource, TDestination> mappingFunction);
并放入您自己的函数,该函数将按名称解析您的 ApplicationDriverEquipmentType假设名称是唯一的,如下所示:

var applicationEquipments = new ApplicationDriverEquipmentTypeRepository().FindAll(); // get all the values somehow from db
var dictionary = applicationEquipments.ToDictionary(x=>x.Name);
Func<string, ApplicationDriverEquipmentType> resolver = x=>dictionary[x]; 

另一种方法是使用 custom value resolver
本质上,这个想法是一样的——预加载对象的映射,只是你 "plug it in" 的方式不同