0

I'm trying to map list of objects to single object, with a nested list.

I have the following class

public class EventLog {
        public string SystemId { get; set; }
        public string UserId { get; set; }
        public List<Event> Events { get; set; }
}

public class Event {
        public string EventId { get; set; }
        public string Message { get; set; }
}

public class EventDTO {
        public string SystemId { get; set; }
        public string UserId { get; set; }
        public string EventId { get; set; }
        public string Message { get; set; }
}

In my List< EventDTO> SystemId and UserId is same for every item in the list.

I want to do exactly reverse of Possible to use AutoMapper to map one object to list of objects?.

Thank you!

2 Answers 2

1

Due to the fact, that your DTOs could contain different SystemIds and / or UserIds, you'll have to group by this criterion before creating your grouped objects. As always, if needed to wave by hand an instance out from a given instance from another type, the catch all method in AutoMapper is .ConvertUsing() and taking an overload that provides a ResolutionContext to allow calling Map() methods within the method itself.

After giving this theoretical introduction, let's come to some real code that solves your problem:

public static class Program
{
    public static void Main(string[] args)
    {
        var dtos = new[] {
            new EventDTO { SystemId = "1", UserId = "10", EventId = $"Event {Guid.NewGuid()}", Message = $"Message {Guid.NewGuid()}" },
            new EventDTO { SystemId = "1", UserId = "20", EventId = $"Event {Guid.NewGuid()}", Message = $"Message {Guid.NewGuid()}" },
            new EventDTO { SystemId = "1", UserId = "30", EventId = $"Event {Guid.NewGuid()}", Message = $"Message {Guid.NewGuid()}" },
            new EventDTO { SystemId = "2", UserId = "10", EventId = $"Event {Guid.NewGuid()}", Message = $"Message {Guid.NewGuid()}" },
            new EventDTO { SystemId = "2", UserId = "20", EventId = $"Event {Guid.NewGuid()}", Message = $"Message {Guid.NewGuid()}" },
            new EventDTO { SystemId = "2", UserId = "30", EventId = $"Event {Guid.NewGuid()}", Message = $"Message {Guid.NewGuid()}" },
        };

        var config = new MapperConfiguration(conf => conf.AddProfile<EventMappingProfile>());
        var mapper = config.CreateMapper();

        // Have to ask for list, cause DTOs could differ in SystemId and/or UserId
        var logs = mapper.Map<List<EventLog>>(dtos);

        // Write result to console
        foreach (var log in logs)
            foreach (var ev in log.Events)
                Console.WriteLine($"{log.SystemId} {log.UserId} {ev.EventId} {ev.Message}");

        Console.ReadKey();
    }

}

public class EventMappingProfile : Profile
{
    public EventMappingProfile()
    {
        CreateMap<EventDTO, Event>();
        CreateMap<IEnumerable<EventDTO>, IEnumerable<EventLog>>()
            .ConvertUsing((dtos, _, context) =>
            {
                return dtos
                    .GroupBy(dto => (dto.SystemId, dto.UserId))
                    .Select(group => new EventLog
                    {
                        SystemId = group.Key.SystemId,
                        UserId = group.Key.UserId,
                        Events = group.Select(context.Mapper.Map<Event>).ToList()
                    })
                    .ToList();
            });
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

You will need to setup the following mapping:

CreateMap<EventDTO, Event>();
CreateMap<EventDTO, EventLog>();
CreateMap<IEnumerable<EventDTO>, EventLog>()
    .ForMember(dest => dest.SystemId, opt => opt.MapFrom(src => src.FirstOrDefault() != null ? src.First().SystemId : ""))
    .ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.FirstOrDefault() != null ? src.First().UserId : ""))
    .ForMember(dest => dest.Events, opt => opt.MapFrom(src => src));

And call the following method:

var eventLog = Mapper.Map<IEnumerable<EventDTO>, EventLog>(events);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.