Search code examples
c#automapperautomapper-2

Am I using Automapper 2.0's Include functionality correctly?


Either I'm not, or it isn't working... I have a single Source class that I want to map to multiple views that inherit from each other.

Basically the base class is the Detail, and the child class is Edit or Update which use all the same data as Detail, plus a couple other fields to manage their own lists or whatever.

Here are the maps I'm using:

Mapper.CreateMap<Ticket, Detail>()
                .Include<Ticket, Update>()
                .Include<Ticket, Edit>()
                .ForMember(dest => dest.Priority, opt => opt.MapFrom(src => src.Priority.Code))
                .ForMember(dest => dest.TicketID, opt => opt.MapFrom(src => src.ID))
                .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusCode))
                .ForMember(dest => dest.Category, opt => opt.MapFrom(src => src.ProblemCategoryCode))
                .ForMember(dest => dest.crmBusCode, opt => opt.MapFrom(src => src.Company.crmBusCode))
                .ForMember(dest => dest.TeamMembers, opt => opt.MapFrom(src => src.Schedules.Where(s => s.CompleteTime == null)));

            Mapper.CreateMap<Ticket, Update>()
                .ForMember(m => m.Schedules, opt => opt.MapFrom(t => t.Schedules.Where(s => s.EmployeeID == Util.CurrentUserID() && s.CompleteTime == null)));

            Mapper.CreateMap<Ticket, Edit>();

Then if I Mapper.Map(ticket) any of the properties that use MapFrom don't get evaluated, they just end up with the values they'd have had if there was no set mapping.

So what's wrong here?


Solution

  • As an alternative solution if you don't want to call Mapper.Map two times. You can move the common mappings of Detail into an extension method:

    public static class MappingExtensions
    {
        public static IMappingExpression<Ticket, TDest> MapDetailProperties<TDest>(
             this IMappingExpression<Ticket, TDest> mapBase) where TDest : Detail
        {
            return mapBase
                .ForMember(dest => dest.Priority, 
                    opt => opt.MapFrom(src => src.Priority.Code))
                 ///....
                .ForMember(dest => dest.TeamMembers, 
                   opt => opt.MapFrom(src => src
                       .Schedules.Where(s => s.CompleteTime == null)));
        }
    }
    

    And then use that extension method when registering the Ticket -> Update and Ticket -> Edit mappers:

    Mapper.CreateMap<Ticket, Update>()
        .MapDetailProperties()
        .ForMember(m => m.Schedules, opt => opt.MapFrom(t => t.Schedules
            .Where(s => s.EmployeeID == Util.CurrentUserID() && 
                s.CompleteTime == null)));
    
    Mapper.CreateMap<Ticket, Edit>()
        .MapDetailProperties();
    

    Then you can use Map normally:

    Ticket ticket = new Ticket();    
    var edit = Mapper.Map<Ticket, Edit>(ticket);
    var update = Mapper.Map<Ticket, Update>(ticket);