Firstly, if my above question is confusing, I am both new to the use of Automapper and don't know the lingo all that well and rarely ask questions like this so I might be trying to articulate my thoughts into an absurd sounding question.
I have created a few classes that inherit from a base class because I intend to re-use the base classes for more entities than the ones shown below. For simplicity sake, I am going to keep the classes void of the properties.
My issue is with the mapping for the PersonBusiness properties. When I load the data from SQL with EF 6 I see it loads the Person and Business properties of the PersonBusiness object as an Employee object and a Branch object because that is what I am pulling back for the query, but when I attempt to map the Employee Object and the Branch object from the PersonBusiness object to the PersonBusinessDto object it loads them as the Person and Business class types; obviously leaving off all the properties that are included in the derived classes.
It's obvious given the data loaded into the PersonBusiness object that the Person and Business properties are object reference variables that can be loaded with the derived types Employee and Branch but for some reason, Automapper sees the Employee and Branch objects and only maps them to the base type of Person and Business.
This is an example of the data loaded from the database:
And this is an example of the data mapped to the PersonBusinessDto:
Below are the basic class structure and the mappings I used to map the Entities to the DTOs which work fine for everything except the PersonBusiness mappings.
Entity.cs
public abstract class Entity : IEntity
{
}
EntityDto.cs
public abstract class EntityDto : IEntityDto
{
}
Person.cs
public abstract class Person : Entity
{
public List<PersonBusiness> PersonBusinesses { get; set; };
}
PersonDto.cs
public abstract class PersonDto : EntityDto
{
public List<PersonBusinessDto> PersonBusinesses { get; set; };
}
Employee.cs
public class Employee : Person
{
}
EmployeeDto.cs
public class EmployeeDto : PersonDto
{
}
Business.cs
public abstract class Business : Entity
{
public List<PersonBusiness> PersonBusinesses { get; set; };
}
BusinessDto.cs
public abstract class BusinessDto : EntityDto
{
public List<PersonBusinessDto> PersonBusinesses { get; set; };
}
Branch.cs
public class Branch : Business
{
}
BranchDto.cs
public class BranchDto : BusinessDto
{
}
PersonBusiness.cs
public class PersonBusiness
{
public int PersonId { get; set; }
public int BusinessId { get; set; }
public Enums.RoleType RoleType { get; set; }
public Person Person { get; set; }
public Business Business { get; set; }
}
PersonBusinessDto.cs
public class PersonBusinessDto
{
public int PersonId { get; set; }
public int BusinessId { get; set; }
public Enums.RoleType RoleType { get; set; }
public PersonDto Person { get; set; }
public BusinessDto Business { get; set; }
}
AutoMapperConfig.cs
public class ProfileMapping
: Profile
{
private readonly IMapperConfiguration _mappingConfiguration;
public ProfileMapping(IMapperConfiguration config)
{
_mappingConfiguration = config;
}
protected override void Configure()
{
_mappingConfiguration.AllowNullDestinationValues = true;
_mappingConfiguration
.CreateMap<Person, PersonDto>()
.ForMember(dto => dto.PersonBusinesses, opt => opt.MapFrom(src => src.PresonBusinesses));
_mappingConfiguration
.CreateMap<Employee, EmployeeDto>()
_mappingConfiguration
.CreateMap<Business, BusinessDto>()
.ForMember(dto => dto.PersonBusinesses, opt => opt.MapFrom(src => src.PresonBusinesses));
_mappingConfiguration
.CreateMap<Branch, BranchDto>();
_mappingConfiguration
.CreateMap<PersonBusiness, PersonBusinessDto>()
.ForMember(dto => dto.Business, opt => opt.MapFrom(src => src.Business))
.ForMember(dto => dto.Person, opt => opt.MapFrom(src => src.Person));
}
}
What's happening here is that Employee
and Branch
are being upcasted to Person
and Business
, respectively since those are the actual types in the PersonBusiness
class. Then, when AutoMapper does the mapping, it sees Person
and Business
types and therefore maps them to PersonDto
and BusinessDto
as the configuration dictates.
The objects are still instances of Employee
and Branch
, even after they've been upcasted; you could cast back to Employee
and Branch
. However, AutoMapper is creating actual instances of PersonDto
and BusinessDto
, so you can't cast those to EmployeDto
and BranchDto
.
Short of having a class with the actual correct property types, you'll have to cast them back to the right types during the mapping, which is going to be a real pain. Principally, you're going to run into the issue that MapFrom
is not going to be able to return varying derived types, because the lambda can only return one type.
AutoMapper provides some guidance for how to make this sort of thing work. However, you'll notice that it's dealing with the instances directly, and not properties on those instances. I'm not sure how to actually, do what you need to do, other than to simply ignore mapping those properties when mapping from PersonBusiness
to PersonBusinessDto
, and then explicitly map over the properties using the method the AutoMapper docs detail, i.e.
personBusinessDto.Person = Mapper.Map(personBusiness.Person, personBusiness.Person.GetType(), typeof(PersonDto));
Like I said: real pain.