Using AutoMapper

AutoMapper is an incredibly useful little tool – it uses conventions and a fluent API to configure and perform mappings between objects.  This is especially useful when using view models – you often end up having to write boilerplate code simply to map between 2 types of objects.

Example

While the AutoMapper project page has some useful examples, I’m going to take a look at something I was recently working on.

public enum CarStatus
{
    ForSale,
    Sold
}

public class Car
{
    public int Id { get; set; }
    public Manufacturer Manufacturer { get; set; }
    public int Year { get; set; }
    public CarStatus Status { get; set; }
}

public class Manufacturer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Model { get; set; }
}

This is the model I would like to map into my view model.

public class CarViewModel
{
    public int Id { get; set; }
    public string ManufacturerName { get; set; }
    public string ManufacturerModel { get; set; }
    public int Year { get; set; }
    public CarStatus Status { get; set; }
}

I could of course simply write the mapping code myself (maybe with a specific constructor), but with AutoMapper I can use conventions to map between my objects and keep the code to a minimum.  Let’s write a unit test to test the mapping.

[Test]
public void DataModel_Should_Map_All_Properties_To_ViewModel()
{
    var dataModel = new Car();
    dataModel.Id = 42;
    dataModel.Manufacturer = new Manufacturer { Id = 12, Name = "Toyota", Model = "Prius" };
    dataModel.Year = 1984;
    dataModel.Status = CarStatus.Sold;

    var viewModel = Mapper.Map<Car,CarViewModel>(dataModel);

    Assert.AreEqual(dataModel.Id, viewModel.Id);
    Assert.AreEqual(dataModel.Manufacturer.Name, viewModel.ManufacturerName);
    Assert.AreEqual(dataModel.Manufacturer.Model, viewModel.ManufacturerModel);
    Assert.AreEqual(dataModel.Year, viewModel.Year);
    Assert.AreEqual(dataModel.Status, viewModel.Status);
}

In typical TDD-fashion I first wrote a failing test and now I’m going to write the code to make it pass.  Using AutoMapper this is just one line of code.

Mapper.CreateMap<Car, CarViewModel>();

Pretty cool.  By default AutoMapper will map all properties of the same name and type – this means the Id, Year and Status properties will automagically be mapped.  AutoMapper also allows you to flatten properties – in this case it knows that the manufacturer’s name property must be mapped to the ManufacturerName property on the view model.  I’m playing nicely by naming my properties correctly, but I think it makes sense and makes our lives a little easier.  If you like you can always use the fluent API to manually define the mappings.

Let’s take a look at the reverse mapping.

[Test]
public void ViewModel_Should_Map_All_Non_Complex_Properties_To_DataModel()
{
    var viewModel = new CarViewModel();
    viewModel.Id = 33;
    viewModel.ManufacturerName = "Nissan";
    viewModel.ManufacturerModel = "GTR";
    viewModel.Year = 2005;
    viewModel.Status = CarStatus.ForSale;

    var dataModel = Mapper.Map<CarViewModel, Car>(viewModel);

    Assert.AreEqual(viewModel.Id, dataModel.Id);
    Assert.AreEqual(viewModel.Year, dataModel.Year);
    Assert.AreEqual(viewModel.Status, dataModel.Status);
    Assert.IsNull(dataModel.Manufacturer);
}

Since I need more context to be able to populate the manufacturer property on my data model I would prefer that the mapping leave the manufacturer null.  Once again I have a failing test and I need to write the code to make it pass.

Mapper.CreateMap<CarViewModel, Car>()
.ForMember(model => model.Manufacturer, x => x.Ignore());

Again I’m relying heavily on the conventions, but I’m also telling AutoMapper to ignore the complex property.  The configuration is straightforward and the fluent API makes it very easy.  Pretty cool.

AutoMapper is a great example of a tool that performs one task and does it very well.  It’s especially useful for MVC applications.  Happy coding.