Here's a simplified example of what I'm trying to do... let's say I have an the following interfaces:
public interface IPerson
{
int Id { get; set; }
}
public interface IModelPerson : IPerson
{
int BeautyCompetitionsWon { get; set; }
}
In the real implementation, there are lots of different types of people (e.g. IUglyPerson
, etc). These are the contracts for entity types, e.g. as follows:
public class PersonEntity : IPerson
{
public int Id { get; set; }
}
public class ModelPersonEntity : PersonEntity, IModelPerson
{
public int BeautyCompetitionsWon { get; set; }
}
Note: We may also have multiple implementations of each contract type - e.g. IModelPerson
may also be implemented by SupermodelEntity
.
We want to map our entity types to DTOs, which look something like this:
public abstract class PersonDto : IPerson
{
public int Id { get; set; }
public abstract string PersonType { get; }
}
public class ModelPersonDto : PersonDto, IModelPerson
{
public int BeautyCompetitionsWon { get; set; }
public override string PersonType
{
get { return "Model"; }
}
}
As such, we create a mapping:
Mapper.Initialize(config =>
{
config.CreateMap<IPerson, PersonDto>()
.Include<IModelPerson, ModelPersonDto>()
.ConstructUsing((IPerson person) =>
{
if (person is IModelPerson) return new ModelPersonDto();
throw new InvalidOperationException("Unknown person type: " + person.GetType().FullName);
})
;
config.CreateMap<IModelPerson, ModelPersonDto>();
});
So, I have two issues here.
1. Is there any way of creating the mappings without the ConstructUsing
clause? I thought that having the more specific version of CreateMap
would have taken care of this for us, but if I don't have the ConstructUsing
clause, AutoMapper tells me "Instances of abstract classes cannot be created".
2. Why don't the properties from my subclasses get mapped? If I execute a mapping as follows:
var source = new ModelPersonEntity { Id = 100, BeautyCompetitionsWon = 9 };
var target = Mapper.Map<PersonDto>(source);
The expected value for target.BeautyCompetitionsWon
is 9, but the actual value is 0.
Question 1: Not that I am aware of.
Question 2: When using the .ConstructUsing()
make sure you return the mapped object you are after rather than a fresh instance.
e.g.
Mapper.Initialize(config =>
{
config.CreateMap<IPerson, PersonDto>()
.Include<IModelPerson, ModelPersonDto>()
.ConstructUsing((IPerson person) =>
{
if (person is IModelPerson) return Mapper.Map<ModelPersonDto>(person);
throw new InvalidOperationException("Unknown person type: " + person.GetType().FullName);
})
;
config.CreateMap<IModelPerson, ModelPersonDto>();
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With