0

I have the following DB (Infrastructure) classes:

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

and the following DTO (Domain) classes:

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

I wrote the following Automapper rules to resolve it:

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

I got an error:

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.

UPDATE

I rewrote maps:

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

but now I got an error:

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

Seems, I don't understand how to map it correctly

Oleg Sh
  • 8,496
  • 17
  • 89
  • 159
  • Type is a string in your class, does it have a name property? – ironstone13 Sep 25 '17 at 17:23
  • @ironstone13, Type is a string for ApplicationDriverEquipmentAbstractDomain class, but has type ApplicationDriverEquipmentType for ApplicationDriverEquipment – Oleg Sh Sep 25 '17 at 17:27
  • Hey, @Oleh Sh, sorry for the wordy and iterative response, but I finally wrote it, please see my answer below. If you have any questions, let me know – ironstone13 Sep 25 '17 at 19:05

2 Answers2

1

You are trying to map from
ApplicationDriverEquipmentTractorDomain.Type is a string
to
ApplicationDriverEquipment.Type is a ApplicationDriverEquipmentType

Where is your mapping configuration for that?

Is it even possible to map a string to a ApplicationDriverEquipmentType?
Sure, you can have a string Name, but where do you get the Id and Equipments?

I suspect you don't want to create a new instance of that type each time you map, but rather you need to look up an instance from some dictionary, sort of a registry pattern

To implement this idea, you simply need to

  1. Load all of the ApplicationDriverEquipmentType from DB
  2. Put them in a dictionary (assuming name is unique)
  3. Register a custom type converter or custom value resolver as below

One way to implement this would be to use a custom type converter
You could use something like
void ConvertUsing(Func<TSource, TDestination> mappingFunction);
And put in your own function that would resolve your ApplicationDriverEquipmentType by name, assuming name is unique like this:

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

Yet another way to do this would be to use a custom value resolver
Essentially, the idea would be the same - map of pre-loaded objects, only the way you "plug it in" would be different

ironstone13
  • 3,325
  • 18
  • 24
0

Try to use MapFrom method instead:

.ForMember(c => c.Type.Name, p => p.MapFrom(s => Domain.StaticStrings.ApplicationDriverEquipmentTypeStaticStringsDomain.Tractor));
Rey
  • 3,663
  • 3
  • 32
  • 55
  • @OlegSh why have you set the Type like this `c => c.Type.Name` in the Mapping logic. As far as I can see it is a simple string property so it must be `c => c.Type` – Rey Sep 25 '17 at 17:59
  • @raimondBurgaj, as you can see, Type has type ApplicationDriverEquipmentType , not string in destination class :) – Oleg Sh Sep 25 '17 at 18:07