Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#

AutoMapper

Rate me:
Please Sign up or sign in to vote.
4.86/5 (137 votes)
1 Mar 2010CPOL5 min read 420.6K   7.1K   193   44
AutoMapper is an object-object mapper which allows you to solve issues with mapping the same properties from one object of one type to another object of another type. For example, mapping a heavy entity Customer object to the CustomerDTO could be done with AutoMapper automatically.

Introduction

AutoMapper is an object-to-object mapper, which allows you to solve issues with mapping of the same properties in one object of one type to another object of another type. For example, mapping a heavy entity Customer object to the CustomerDTO could be done with AutoMapper automatically.

The Problem

Have you ever had to write code like this:

C#
Customer customer = GetCustomerFromDB();

CustomerViewItem customerViewItem = new CustomerViewItem()
                           {
                               FirstName = customer.FirstName,
                               LastName = customer.LastName,
                               DateOfBirth = customer.DateOfBirth,
                               NumberOfOrders = customer.NumberOfOrders
                           };

ShowCustomerInDataGrid(customerViewItem);

A sample scenario could be:

We have our domain model which has a Customer entity, and we are going to show Customers in a DataGrid, and for that, we need a much lighter object CustomerViewItem, a list of which is bound to a grid.

As you see, there are four lines of code which just copy the values from one object to another. It could also be that you will need to show up to 10-15 columns in your grid. What then?

Would you like to have something that will do mapping from Customer to the CustomerViewItem automatically?

Of course, you do, especially if you have another situation like mapping of heavy data objects into DTO objects which are considered to be sent though the wire.

AutoMapper (The Solution)

From the AutoMapper CodePlex web page, we can see that "AutoMapper is an object-object mapper. Object-object mapping works by transforming an input object of one type into an output object of a different type. What makes AutoMapper interesting is that it provides some interesting conventions to take the dirty work out of figuring out how to map type A to type B. As long as type B follows AutoMapper's established conventions, almost zero configuration is needed to map two types." So, in other words, it provides the solution for our problem.

Get Started

To get started, go and download it here. It is a standalone assembly, so you should not have difficulties including a reference to it in your project.

In order to ask AutoMapper to do the dirty work instead of me, we need to add this line somewhere in the start of our code execution:

C#
Mapper.CreateMap<Customer, CustomerViewItem>();

Once we have that, we are done, and we can use this code to get our mapped object:

C#
Customer customer = GetCustomerFromDB();

CustomerViewItem customerViewItem = 
   Mapper.Map<Customer, CustomerViewItem>(customer);

ShowCustomerInDataGrid(customerViewItem);

Let's take a look at the whole code base to see all about what I'm going to talk further:

C#
class Program
{
    static void Main(string[] args)
    {
        var program = new Program();
        Mapper.CreateMap<Customer, CustomerViewItem>();
        program.Run();
    }

    private void Run()
    {
        Customer customer = GetCustomerFromDB();

        CustomerViewItem customerViewItem = 
          Mapper.Map<Customer, CustomerViewItem>(customer);

        ShowCustomerInDataGrid(customerViewItem);
    }

    private void ShowCustomerInDataGrid(
                   CustomerViewItem customerViewItem){}

    private Customer GetCustomerFromDB()
    {
        return new Customer()
        {
            DateOfBirth = new DateTime(1987, 11, 2),
            FirstName = "Andriy",
            LastName = "Buday",
            NumberOfOrders = 7
        };
    }
}

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }

    public int NumberOfOrders { get; set; }
}

public class CustomerViewItem
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }

    public int NumberOfOrders { get; set; }
}

And to prove that all values have been mapped, take a look at this picture:

Image 1

More Complex Example 1 (Custom Map)

So far, we know all about doing an extremely simple mapping. But, what if we need something more complex, for example, CustomerViewItem should have FullName, which consists of the first and last names of Customer?

After I added public string FullName { get; set; } to CustomerViewItem and run my application in Debug mode, I got a null in the property. That is fine, and is because AutoMapper doesn't see any FullName property in the Customer class. In order to "open its eyes", all you need to do is to change our CreateMap process a bit:

C#
Mapper.CreateMap<Customer, CustomerViewItem>()
    .ForMember(cv => cv.FullName, m => m.MapFrom(
    s => s.FirstName + " " + s.LastName))

And results are obtained immediately:

Image 2

More Complex Example 2 (Flattening)

What if you have a property Company of type Company:

C#
public class Customer
{
    public Company Company { get; set; }
    //...
}

public class Company
{
    public string Name { get; set; }
}

and want to map it into CompanyName of the view class:

C#
public class CustomerViewItem
{
    public string CompanyName { get; set; }
    //...
}

What do you need to change in your mapping to make this work?

Answer: Nothing. AutoMapper goes in to the depth of your classes, and if names match, it will do the mapping for you.

More Complex Example 3 (Custom Type Resolvers)

What if you have a boolean property VIP in your Customer class?

C#
public class Customer
{
    public bool VIP { get; set; }
}

and want to map it into a string VIP and represented like "Y" or "N" instead?

C#
public class CustomerViewItem
{
    public string VIP { get; set; }
}

Well, we can solve this the same way we did for FullName, but a more appropriate way is to use custom resolvers. So, let's create a customer resolver which will resolve the VIP issue for us.

It looks like:

C#
public class VIPResolver : ValueResolver<bool, string>
{
    protected override string ResolveCore(bool source)
    {
        return source ? "Y" : "N";
    }
}

And, only one line is needed for our CreateMap process:

C#
.ForMember(cv => cv.VIP, m => m.ResolveUsing<VIPResolver>().FromMember(x => x.VIP));

More Complex Example 4 (Custom Formatters)

What if I want AutoMapper to use my custom formatting of DateTime instead of just using ToString, when it does a mapping from a DateTime to a String property? Let's say, I want to use the ToLongDateString method to show the birth date in a different fashion.

For that, we add:

C#
public class DateFormatter:IValueFormatter
{
    public string FormatValue(ResolutionContext context)
    {
        return ((DateTime) context.SourceValue).ToLongDateString();
    }
}

And make sure that AutoMapper knows where to use it:

C#
.ForMember(cv => cv.DateOfBirth, m => m.AddFormatter<DateFormatter>());

So now, I've got:

Image 3

Great, isn't it? BirthDate is even shown in my native language.

Performance Question

After I posted this article, one guy was really concerned about the performance of AutoMapper. So, I have decided to measure execution time of the AutoMapper mapping and manual mapping code.

First of all, I have code which returns me 100000 almost random Customers which goes to the customers list.

Measurement of AutoMapper mapping time:

C#
stopwatch.Start();
var autoMapperCVI = new List<customerviewitem>();
foreach (var customer in customers)
{
   autoMapperCVI.Add(Mapper.Map<customer,customerviewitem>(customer));
}
stopwatch.Stop();
Console.WriteLine(string.Format("AutoMapper: {0}", stopwatch.ElapsedMilliseconds));

Measurement of the manual mapping time:

C#
stopwatch.Start();
var manualCVI = new List<customerviewitem>();
foreach (var customer in customers)
{
        var customerViewItem = new CustomerViewItem()
		{
                     	FirstName = customer.FirstName,
                    	LastName = customer.LastName,
                 		FullName = customer.LastName + " " + customer.FirstName,
          		DateOfBirth = customer.DateOfBirth.ToLongDateString(),
           		CompanyName = customer.Company.Name,
              		NumberOfOrders = customer.NumberOfOrders,
           		VIP = customer.VIP ? "Y" : "N"
		};
        manualCVI.Add(customerViewItem);
}

stopwatch.Stop();            
Console.WriteLine(string.Format("Manual Mapping: {0}", stopwatch.ElapsedMilliseconds));

I ran my tests many times and one of the possible outputs could be:

AutoMapper: 2117
Manual Mapping: 293

It looks like manual mapping is 7 times faster than automatic. But hey, it took 2 secs to map hundred thousands of customers.

It is one of the situations where you should decide if the performance is so critical for you or no. I don't think that there are a lot of cases when you really need to choose manual mapping exactly because of performance issue.

Points of Interest

I hope my article was interesting to read and that it gave you ideas for how you can utilize this new feature called "AutoMapper".

Go to the AutoMapper website for more information.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer SoftServe
Ukraine Ukraine
I'm very pragmatic and self-improving person. My goal is to become successful community developer.
I'm young and love learning, these are precondition to my success.

Currently I'm working in dedicated Ukrainian outsourcing company SoftServe as .NET developer on enterprise project. In everyday work I'm interacting with lot of technologies which are close to .NET (NHibernate, UnitTesting, StructureMap, WCF, Win/WebServices, and so on...)

Feel free to contact me.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Philip.F25-Sep-12 3:41
Philip.F25-Sep-12 3:41 
GeneralMy vote of 5 Pin
Ritesh_Prasad2-Apr-12 1:47
Ritesh_Prasad2-Apr-12 1:47 
QuestionError detection Pin
Brendan Chong29-Mar-12 18:29
Brendan Chong29-Mar-12 18:29 
QuestionConcept understood, but I don't agree. Pin
todd.deland11-Oct-11 11:13
todd.deland11-Oct-11 11:13 
AnswerRe: Concept understood, but I don't agree. Pin
pboy32119-Feb-13 9:53
pboy32119-Feb-13 9:53 
GeneralMy vote of 5 Pin
sekhar shrivastava10-Oct-11 3:40
sekhar shrivastava10-Oct-11 3:40 
QuestionHow to use ValueResolver with GUID? Pin
Sunasara Imdadhusen7-Oct-11 19:52
professionalSunasara Imdadhusen7-Oct-11 19:52 
AnswerRe: How to use ValueResolver with GUID? Pin
Jalal Khordadi11-Aug-12 22:51
Jalal Khordadi11-Aug-12 22:51 
You should not do it in your ValueResolver! because it's just for mapping an object to another, not for checking unique data in db or anywhere else.
The philosophers have only interpreted the world in various ways; The point however is to change it!
-Karl Marx-

GeneralExcellent! Pin
Sunasara Imdadhusen6-Oct-11 23:23
professionalSunasara Imdadhusen6-Oct-11 23:23 
GeneralNice Article Pin
Ekta Mehta14-Feb-11 2:56
Ekta Mehta14-Feb-11 2:56 
QuestionDoes this OO/M support framework 2.0 also ? Pin
Berlus27-Mar-10 19:21
Berlus27-Mar-10 19:21 
AnswerRe: Does this OO/M support framework 2.0 also ? Pin
Andriy Buday28-Mar-10 5:31
Andriy Buday28-Mar-10 5:31 
GeneralFaster solution Pin
Milos Tomic22-Mar-10 21:12
Milos Tomic22-Mar-10 21:12 
GeneralRe: Faster solution Pin
Matt Sollars29-Mar-10 9:45
Matt Sollars29-Mar-10 9:45 
GeneralAre there any samples of how to use EmitMapper? Pin
SteveMets20-Dec-13 9:42
professionalSteveMets20-Dec-13 9:42 
GeneralAwesome article! Pin
User 46779167-Mar-10 17:44
User 46779167-Mar-10 17:44 
GeneralRe: Awesome article! Pin
Andriy Buday7-Mar-10 22:38
Andriy Buday7-Mar-10 22:38 
GeneralTypo Pin
Steve Hansen26-Feb-10 4:52
Steve Hansen26-Feb-10 4:52 
GeneralRe: Typo Pin
Andriy Buday26-Feb-10 4:55
Andriy Buday26-Feb-10 4:55 
GeneralRe: Typo Pin
Andriy Buday26-Feb-10 5:02
Andriy Buday26-Feb-10 5:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.