Sunday, February 28, 2010

Question about AutoMapper Performance



If you haven't read my previous article on AutoMapper, please read it first.


After I've 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:


            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:


            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 automatical. But hey, it took 2 sec to map handrend thouthands 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 choice manual mapping exactly because of performance issue.

Saturday, February 27, 2010

I wanna be not so noisy and decoupled to AutoMapper

If you haven't read my previous article on AutoMapper, please read it first.

I just read an article on the noisiness which could be introduced with AutoMapper.

My Mapping Code is Noisy

Accordingly to that article my code:

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

is noisy code.

Why?

In few words that is because I'm coupled to the specific mapping engine and because I'm providing too much unneeded information on about how to map my objects.
Take a look on that line once again: we used Customer , but we already have customer, so we can know its type.


What to do to make it not so noisy?


In that article, that I pointed, there is proposition to change my code to:


            CustomerViewItem customerViewItem = customer.Map<CustomerViewItem>();


So, I've got interested to apply it to my previous AutoMapper article's code. As you already caught Map is just extension method for my Customer  class.


Here it is:


    public static class MappingExtentions
    {
        public static TDest Map<TDest>(this Customer customer)
        {
            return Mapper.Map<Customer, TDest>(customer);
        }
    }


Everything becomes simple if you are trying it.

Constraints for my Generics


I have never used constraints for my generic classes. So in this article I just want to show how I've used it:

So for now I have ICustomer interface:


    public interface ICustomer
    {
        string Name { getset; }
        List<int> GetOrders();
    }


and two implementations like UsualCustomer and VipCustomer.

Also I'm going to have some OrderingProcessor which is supposed to be operating with different types of Customers. But when I want to call GetOrders method I just have not it in my list, like below:



but once I've changed the declaration of the OrderingProcess just a little bit, with specifying type of T


    public interface IOrderingProcessor<T>
        where T : ICustomer
    {
        void Process(T objectToProcess);
    }


World has smiled to me and I'm getting what I want, please see:



I expect that you are laughing while reading this post. Maybe because this thing is too simple to write article/post on it if you are familiar with C#/.NET. Yes, but I have never tried it myself. Did you?

To make you laughing not so much loud let us take a look on another architecture:


    public interface IOrderingProcessor<T>
        where T : ICustomer
    {
        void Process(T objectToProcess);
    }

    internal class VipOrderingProcessor<TCustomer> : IOrderingProcessor<TCustomer>
        where TCustomer : IVipCustomernew()
    {
        public void Process(TCustomer objectToProcess)
        {
            var vipCustomer = new TCustomer();

            var orders = objectToProcess.GetOrders();
        }
    }


As you see we can create specific VipOrderingProcessor and we are constraining it to use just VipCustomers or derived classes. This gives us opportunity to specify constraints on different levels of implementation.

But do you know what does another constraint  new() mean?
This constraint specifies that TCustomer objects will have public default constructor, so you can write

            var vipCustomer = new TCustomer();

This could be very useful for implementing Factory Design Pattern. I'm sure that next time I will need to develop whole family of Factories I will use constraints, since code could be much flexible in this case.

Friday, February 26, 2010

AutoMapper


The Problem

Have you ever faced need to write code, which looks like here:


            Customer customer = GetCustomerFromDB();

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

            ShowCustomerInDataGrid(customerViewItem);


Our scenario could be like:
We have our domain model which has Customer entity and we are going to show Customers in DataGrid, and for that we need much lighter object CustomerViewItem, list of which is bounded to the Grid.

As you see there are four lines of code which are just copying values from one object to another. Could also be that you will need to show up to 10-15 columns in you 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 send though the wire.

AutoMapper

From the AutoMapper codeplex web page we 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 convention, almost zero configuration is needed to map two types.", so in other words it provides the solution for our problem.

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

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

            Mapper.CreateMap<Customer, CustomerViewItem>();

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


            Customer customer = GetCustomerFromDB();

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

            ShowCustomerInDataGrid(customerViewItem);


Lets take a look on whole code base to see all about what I'm going to talk further:


    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 proving that all values has been mapped take a look on the picture:



More Complex Example 1 (Custom Map)

So far we know all to have extremely simple mapping. But what if we need something more complex, for example, CustomerViewItem should have FullName, which consists with First and Last names of Customer?

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


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

And results are immediately:



More Complex Example 2 (Flattening)

What if you have property Company of type Company:


    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


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

How do you think what do you need to change in your mapping to make this work?

Answer: NOTHING. AutoMapper goes in deep of your classes and if names matches it will do mapping for you.

More Complex Example 3 (Custom type resolvers)

What if you have boolean property VIP in your Customer class:

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

and want to map it into string VIP and represent like "Y" or "N" instead


    public class CustomerViewItem
    {
        public string VIP { get; set; }
    }
   
Well, we can solve this the same way we did for the FullName, but more appropriate way is to use custom resolvers.
So lets create customer resolver which will resolve VIP issue for us.

It looks like:


    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:

    .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 the DateTime instead of just using ToString, when it does mapping from DateTime to String property?
Let say I want use ToLongDateString method to show birth date with fashion.

For that we add:


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

And making sure that AutoMapper knows where to use it:

                .ForMember(cv => cv.DateOfBirth, m => m.AddFormatter<DateFormatter>());
So, now I've got:


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

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