-1

I have a problem mapping one of my DTOs which have a collection, to the flattened version in the entity model.

Here's the DTO classes:

public class Location {
   public int LocationId {get; set;}
   public string LocationName {get;set;}
   public List<HoursOfOperation> HoursOfOperation {get; set;}
}

public class HoursOfOperation {
      public int WeekNumber {get; set;}
      public int DayNumber {get; set;}
      public List<TimeSlot> OperatingHours {get; set;}
}

public class TimeSlot{
      public TimeSpan StartTime {get; set;}
      public TimeSpan EndTime { get; set;}
}

Here's my entity model class:

 public partial class HoursOfOperation
    {
        public int HoursOfOperationId { get; set; }
        public int FkLocationId { get; set; }
        public short WeekNumber { get; set; }
        public short DayNumber { get; set; }
        public TimeSpan StartTime { get; set; }
        public TimeSpan EndTime { get; set; }
    }

I've used Automapper and got this far:

public OpHoursMappingProfile()
    {
        CreateMap<HoursOfOperation, Models.ClientDb.HoursOfOperation>()
            .ForMember(dest => Enum.GetName(typeof(DayOfWeek), dest.DayNumber), opt => opt.MapFrom(t => t.DayNumber))
            .ForMember(dest => dest.WeekNumber, opt => opt.MapFrom(t => t.WeekNumber));
    }

I'm not sure how to map the timeslots. I tried creating a custom extension as explained here, but it didn't help.

devC
  • 1,384
  • 5
  • 32
  • 56
  • Use `Max()` for `EndTime` and `Min()` for `StartTime`. For example to get end time: `.ForMember(dst => dst.EndTime, opt => opt.MapFrom(t => t.OperatingHours.Max(hours => hours.EndTime)))`. – Prolog Dec 27 '19 at 20:02
  • @Prolog: actually, what I want is to create a HoursOfOperation entity for each timeslot. So if the DTO has 3 timeslots for a given day, that will create 3 HoursOfOperation records in the DB. – devC Jan 01 '20 at 04:50

1 Answers1

0

Your comment give me a better insight into what you are trying to achieve and it seems to me that it is mapping single source object to a collection of destination objects. For that to happen, I would suggest creating custom type converter:

public class HoursOfOperationConverter : ITypeConverter<HoursOfOperation, IEnumerable<Models.ClientDb.HoursOfOperation>>
{
    public IEnumerable<Models.ClientDb.HoursOfOperation> Convert(
        HoursOfOperation source,
        IEnumerable<Models.ClientDb.HoursOfOperation> destination,
        ResolutionContext context)
    {
        foreach (var timeSlot in source.OperatingHours)
        {
            var hours = context.Mapper.Map<Models.ClientDb.HoursOfOperation>(source);
            hours = context.Mapper.Map(timeSlot, hours);

            yield return hours;
        }
    }
}

Notice how converter is mapping to HoursOfOperation twice in every iteration. First time from original hours of operation DTO, so regular properties like FkLocationId can be filled. Second time from current time slot, so StartTime and EndTime dates can be filled from corresponding time slot. It is also important to understand why at second time mapping to an existing object is used. It is so because otherwise the result of the first mapping would be lost.

Mapping profile:

public class OpHoursMappingProfile : Profile
{
    CreateMap<HoursOfOperation, Models.ClientDb.HoursOfOperation>()
        .ForMember(
            destination => destination.HoursOfOperationId,
            options => options.MapFrom(source => source.Id))
        .ForMember(
            destination => destination.FkLocationId,
            options => options.MapFrom(source => source.LocationId));
    CreateMap<TimeSlot, Models.ClientDb.HoursOfOperation>();
    CreateMap<HoursOfOperation, IEnumerable<Models.ClientDb.HoursOfOperation>>()
        .ConvertUsing<HoursOfOperationConverter>();
}

I do not understand fully your week/day number mappings, so I left them for you to implement.

Example usage:

var result = mapper.Map<IEnumerable<Models.ClientDb.HoursOfOperation>>(hours);
Prolog
  • 2,698
  • 1
  • 18
  • 31