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!
CodePudding user response:
Due to the fact, that your DTOs could contain different SystemId
s and / or UserId
s, 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();
});
}
}
CodePudding user response:
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);