2

First of all, sorry my English :)

I am using AutoMapper to map between classes.

I have structure of classes like the below.

public class OrderDto {
  int Id { get; set; }
}

public class OrderDtoList {
  OrderDto[] Orders { get; set; }
}

public class Order {
  int Id { get; set; }
}

My issue is that, I want to map OrderDtoList object to List using AutoMapping Profile.

public class OrderMappingProfile : Profile {
  public OrderMappingProfile() {
    CreateMap<OrderDto, Order>();
    CreateMap<OrderDtoList, List<Order>(); // <<<<<<<< I cannot figure out this.
  }
}

But I cannot figure out how to write CreateMap<>() function.

Please help.

1
  • You already using conversion of OrderDto to Order (or reverse). Still if this is necessary for you, you can use @Alex Petrescu 's answer for solution. Commented Jan 8, 2020 at 15:31

3 Answers 3

5

You can create a class which implements ITypeConverter< OrderDtoList, List > and create the mapping using ConvertUsing method.

public class OrderDtoListMapper : ITypeConverter<OrderDtoList, List<Order>>
{
    public List<Order> Convert(OrderDtoList source, List<Order> destination, ResolutionContext context)
    {
        return context.Mapper.Map<List<Order>>(source.Orders);
    }
}

Then, you can create your mapping like this:

public class MapperProfile : Profile
{
    public MapperProfile()
    {
        CreateMap<OrderDto, Order>();
        CreateMap<OrderDtoList, List<Order>>().ConvertUsing<OrderDtoListMapper>();
    }
}

Hope this is what you were looking for!

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for helping. It is work for me. I missed using ResolutionContext context.
You don't need to iterate over the collection, map each object and materialize the result into a new list. This does AutoMapper out of the box, if you map a collection to another kind of collection and a mapper is defined for the source to destination elements.
3

It's a little difficult to get it from scratch, but it is possible. You have to create a ITypeConverter<,> and apply this to be used for the conversion.

Be aware, that the ConvertUsing() method has also an overload to simply add an inline function, but you need to have access to the mapper itself to call it for mapping the inner objects to the desired result objects and that's only available with the type converter interface.

public class OrderMappingProfile : Profile
{
    public OrderMappingProfile()
    {
        CreateMap<OrderDto, Order>();
        CreateMap<OrderDtoList, List<Order>>().ConvertUsing<CustomConverter>();
    }
}

public class CustomConverter : ITypeConverter<OrderDtoList, List<Order>>
{
    public List<Order> Convert(OrderDtoList source, List<Order> destination, ResolutionContext context)
    {
        return context.Mapper.Map<List<Order>>(source.Orders);
    }
}

With this in place, you can create the desired list right from the DTO:

public static class Program
{
    public static void Main()
    {
        var config = new MapperConfiguration(cfg => cfg.AddProfile<OrderMappingProfile>());
        var mapper = config.CreateMapper();

        var orderList = new OrderDtoList { Orders = Enumerable.Range(1, 10).Select(i => new OrderDto { Id = i }).ToArray() };
        var orders = mapper.Map<List<Order>>(orderList);
    }
}

As Lucian mentioned, there is an overload of ConvertUsing() that provides the context. So you could also inline this, instead of using an own class:

// Use lambda method
CreateMap<OrderDtoList, List<Order>>()
    .ConvertUsing((source, _, context) => context.Mapper.Map<List<Order>>(source.Orders));

// Use static method
CreateMap<OrderDtoList, List<Order>>().ConvertUsing(ListConverter);

private static List<Order> ListConverter(OrderDtoList source, List<Order> destination, ResolutionContext context)
{
    return context.Mapper.Map<List<Order>>(source.Orders);
}

2 Comments

Actually there is a ConvertUsing lambda overload that receives the context.
@LucianBargaoanu: Yes, you're right. Just updated my answer.
-1

below is a generic extension, if you have not used an extension before please observe that the GenericExtensions class is a static class

public static class GenericExtensions {
   public static object Map<T>(this T source)
    {
        var fullName = source.GetType().FullName;
        var sourceType = source.GetType();


        var baseType = ObjectContext.GetObjectType(source.GetType());

        var config = new MapperConfiguration(cfg =>
            cfg.CreateMap(sourceType, baseType));




        var mapper = config.CreateMapper();

        var entity = mapper.Map(source, sourceType, baseType);

        return entity;

    }

}

public static List<T> Map<T>(this List<T> original)
{
        var config = new MapperConfiguration(cfg =>
            cfg.CreateMap(typeof(T), typeof(T)));

        var mapper = config.CreateMapper();       
        return original.Select(mapper.Map<T, T>).ToList();
}

Usage:

for single entity:

var originalObject = new  Order();
originalObject.Id = 4; 
var clonedObject = originalObject.Map();

for list of entities:

var objectList = db.ORDERS.ToList();
var clonedList = objectList.Map();

Hope this helps!

4 Comments

What is type of cloneObject? I think it is same type with originalObject. I do not want to like this.
yes, this is a generic extension method so you can clone any entity, what is it that you want? to clone a list?
Yes, I want to like this. var dtoObject = new OrderDtoList { Orders = new List<OrderDto>() }; List<Order> list = mapper.Map<List<Order>>(dtoObject); So, I want to convert orders property in OrderDtoList object to List<Order>
I have added a second method Hakan, using these two extension methods you can easily clone any type of entity or list of entities.

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.