I try to figure out how to flatten a collection of Merchants, each containing a collection of Orders to a flat List of OrderViewModels.
Here my DTO:
public class Merchant
{
public string MerchantName { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public string OrderId { get; set; }
}
And Here's the view model:
public class OrderViewModel
{
public string MerchantName { get; set; }
public string OrderId { get; set; }
}
My Goal is to flatten a List<Merchant> to a List<OrderViewModel> whereas the following test structure should result in 6 view models:
var myMerchants = new List<Merchant>
{
new Merchant
{
MerchantName = "Merchant X",
Orders = new List<Order>
{
new Order { OrderId = "Order 1"},
new Order { OrderId = "Order 2"},
new Order { OrderId = "Order 3"}
}
},
new Merchant
{
MerchantName = "Merchant Y",
Orders = new List<Order>
{
new Order { OrderId = "Order 4"},
new Order { OrderId = "Order 5"},
new Order { OrderId = "Order 6"}
}
}
};
var models = Mapper.Map<List<OrderViewModel>>(myMerchants);
Because the cardinality of the root objects isn't 1:1, (i.e. 2 root Merchants
need to map to 6 OrderViewModels
), you may need to resort to a custom TypeConverter
and operate at the collection level, where you can use .SelectMany
to do the flattening:
public class MyTypeConverter : ITypeConverter<IEnumerable<Merchant>, List<OrderViewModel>>
{
public List<OrderViewModel> Convert(ResolutionContext context)
{
if (context == null || context.IsSourceValueNull)
return null;
var source = context.SourceValue as IEnumerable<Merchant>;
return source
.SelectMany(s => s.Orders
.Select(o => new OrderViewModel
{
MerchantName = s.MerchantName,
OrderId = o.OrderId
}))
.ToList();
}
}
Which you can then bootstrap:
Mapper.CreateMap<IEnumerable<Merchant>, List<OrderViewModel>>()
.ConvertUsing<MyTypeConverter>();
And then mapped as such:
var models = Mapper.Map<List<OrderViewModel>>(myMerchants);
An interesting finding is that, only do the below is enough to achieve the goal without automapper.
var models = myMerchants.SelectMany(s => s.Orders.Select(o => new OrderViewModel { MerchantName = s.MerchantName, OrderId = o.OrderId })).ToList();
Old question but thought would be helpful for newer versions.
I am using .Net core 2 with automapper. I prefer to do the ProjectTo extension of queryable
queryable
.SelectMany(outterClass => outterClass.innerList)
.AsQueryable()
.ProjectTo<OutterClassDto>();
Then, configure like so:
config.CreateMap<OuterClass, OuterClassDto>();