Search code examples
c#automapperchildrendto

AutoMapper with different children


I have an entity as Plan with multiple sub-plans (children), each of which could be null.

For the PlanDto, I am trying to load up a list of all children rather than having a separate property for each child like the entity.

I have already achieved it manually through a foreach loop but now I am trying to do it via AutoMapper, which is failing for some reason.

Entities:

public class Plan
{
    public virtual int Id { get; set; }
    public DateTime Date { get; set; }
    public virtual PlanDetail PlanChild1 { get; set; }
    public virtual ObservationCare PlanChild2 { get; set; }
}

public class PlanDetail
{
    public virtual int Id { get; set; }
    public virtual Plan Plan { get; set; }
    public virtual string Description { get; set; }
}

public class ObservationCare
{
    public virtual int Id { get; set; }
    public virtual Plan Plan { get; set; }
    public virtual string Description { get; set; }
}

DTOs:

public class PlanDto: EntityDto
{
    public DateTime Date { get; set; }
    public IEnumerable<ChildPlan> ChildPlan { get; set; }
}

public class ChildPlan : EntityDto
{
    public ChildPlanType Type { get; set; }
}

public enum ChildPlanType
{
    PlanDetail,
    ObservationCare
}

AutoMapper config:

configuration.CreateMap<Plan, PlanDto>();

configuration.CreateMap<PlanDetail, ChildPlan>()
    .ForMember(dto => dto.Type, options => options.MapFrom(p => ChildPlanType.PlanDetail));

configuration.CreateMap<ObservationCare, ChildPlan>()
    .ForMember(dto => dto.Type, options => options.MapFrom(p => ChildPlanType.ObservationCare));

Mapping attempt:

var output = new List<PlanDto>();
var plans = await _planRepository.GetAll().ToList();
foreach (var plan in plans)
{
    output.Add(ObjectMapper.Map<PlanDto>(plan));
}

I do not know why ChildPlan DTOs in the output list are always null!


Solution

  • You have to specify the mapping for PlanDto.ChildPlan:

    configuration.CreateMap<Plan, PlanDto>()
        .ForMember(dto => dto.ChildPlan,
            options => options.MapFrom(
                p => new object[] { p.PlanChild1, p.PlanChild2 }.Where(c => c != null)));
    

    If you are using Entity Framework Core, you have to use eager-loading:

    var plans = await _planRepository.GetAll()
        .Include(p => p.PlanChild1)
        .Include(p => p.PlanChild2)
        .ToList();
    

    There's also a simpler and more efficient way to map a list:

    var output = ObjectMapper.Map<List<PlanDto>>(plans);