1

My application needs to display a table of customer data, including data about the customer and about his most recent order from a given warehouse. The customer domain object contains a GetLatestOrder(warehouseId) method.

I have a CustomerView viewmodel and want to be able to populate it with some fields from the customer object, and a few fields from the latest order object. Can I do this using Automapper?

3 Answers 3

4

Try this,

In Global.asax.cs [Application_Start], public static void AppInitialize()

    protected void Application_Start(object sender, EventArgs e)
    {
        Mapper.CreateMap<Order, CustomerViewModel>()
             .ForMember(destination => destination.OrderId, options => options.MapFrom(source => source.Id))
             .ForMember(destination => destination.OrderName, options => options.MapFrom(source => source.Name));
        Mapper.CreateMap<Customer, CustomerViewModel>()
             .ForMember(destination => destination.CustmerId, options => options.MapFrom(source => source.Id))
             .ForMember(destination => destination.CustmerName, options => options.MapFrom(source => source.Name))
             .ForMember(destination => destination.OrderId, options => options.MapFrom(source => Mapper.Map<IEnumerable<Order>, IEnumerable<CustomerViewModel>>(source.Orders).FirstOrDefault().OrderId))
             .ForMember(destination => destination.OrderName, options => options.MapFrom(source => Mapper.Map<IEnumerable<Order>, IEnumerable<CustomerViewModel>>(source.Orders).FirstOrDefault().OrderName));
    }

And in your code call the mapper like below,

        var lstCustomers = new List<Customer>
        {
            new Customer { Id = 1, Name="Name", Orders = new List<Order> { new Order { Id = 1000, Name ="Some Name"}}},
        };

        var result = Mapper.Map<IEnumerable<Customer>, IEnumerable<CustomerViewModel>>(lstCustomers);

I am presumed that you classes looks like below,

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Order> Orders { get; set; }
}

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

public class CustomerViewModel
{
    public int CustmerId { get; set; }
    public string CustmerName { get; set; }
    public int OrderId { get; set; }
    public string OrderName { get; set; }
}

Also refer this post.

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

2 Comments

Thanks @Prasad Kanaparthi. The scenario is very like the one you describe, but there is one crucial difference. The single row from the Orders entity has to be filtered by WarehouseId, and this value is not available during Application_Start, only during controller method execution.
@PaulTaylor Can you please post your requirement with sample code. If i understand correctly, i guess you cannot do filtered by warehouseid in application_start using automapper. instead you can do another way. please post the details. thanks
1

Yes, you can:

var vm = new CustomerViewModel();
Mapper.Map(customer, vm);
Mapper.Map(order, vm);

Each mapping will populate the properties it is configured to and leave the rest.

6 Comments

Thanks, yes that works for individual customers, but I need to be able to populate a collection of customers and include details of an order retrieved by calling a method (I need to pass a parameter to the method, so the mapping can't be achieved at Automapper configuration time). Any ideas?
If you could create that method as static or put it on your Customer class you could use AfterMap at the configuration time. If not, then I'm not sure if you will get through without creating a proxy class that will then be passed to the AutoMapper.
@Knagís, thanks for the tip about AfterMap, haven't seen that. The method in question is on the Customer class. Will give that a go. But, looking at an example of AfterMap, it seems you have to pass any arguments to the AfterMap delegate at configuration time. Unfortunately, the value to pass is not available until the action method is called in the MVC controller: Mapper.CreateMap<Customer, CustomerView>() .AfterMap((c, cv) => c.GetLatestOrder(WarehouseId));
... continued [Sorry, my edit timed out on the last comment]. The above code will not work in Application_Start, because WarehouseId is not available. I understand from Automapper docs that CreateMap needs to be called during the Application_Start event.
I would probably just go the KIS way and just iterate through the collection and do the second mapping manually...
|
1

In the end, I took the easy approach, couldn't find another way:

In Application_start:

    Mapper.CreateMap<Customer, CustomerView>();
    Mapper.CreateMap<Order, CustomerView>();

In the controller method:

    IEnumerable<Customer> customers = GetCustomers(false)
                                               .OrderBy(c => c.Name);
    IEnumerable<CustomerView> viewData = Mapper.Map<IEnumerable<Customer>, IEnumerable<CustomerView>>(customers);
    foreach (Customer customer in customers)
    {
        CustomerView view = viewData.Where(cv => cv.CustomerId == customer.CustomerId).First();
        Mapper.Map(customer.GetLatestOrder(WarehouseId), view);
    }

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.