Wednesday, 28 April 2010

Using Automapper to map entities with similar property names

We started to use a tool from http://automapper.codeplex.com/ that can be used to map entities with similar properties together. We need this when transferring small amounts of data from one database to another. When you download this DLL to the your External libraries directory you will need to right mouse click on it and look at it’s properties because since it might be blocked. If it is blocked just click on the unblock button. First it’s a good practice to wrap third party libraries in a wrapper. We did this in the following self initializing static class. The first time a mapping is required the Initialize method is called.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ccp.Entities;
using AutoMapper;

namespace Ccp.Infrastructure
{
    /// <summary>
    /// Mapper to convert entity to entity.
    /// </summary>
    public static class EntityMapper
    {
        private static bool IsInitialized = false;

        /// <summary>
        /// Create all the static entity mapping declarations for the current process/AppDomain.
        /// </summary>
        internal static void Initialize()
        {
            Mappings.Initialize();
            IsInitialized = true;
        }

        /// <summary>
        /// Convert the source type object into a destination type object.
        /// </summary>
        /// <typeparam name="TSource">The type of the source entity.</typeparam>
        /// <typeparam name="TDest">The type of the destination entity.</typeparam>
        /// <param name="source">The source object.</param>
        /// <returns>The destination object.</returns>
        public static TDest Map<TSource, TDest>(TSource source)
        {
            if (!IsInitialized)
            {
                Initialize();
            }

            TDest dest = Mapper.Map<TSource, TDest>(source);
            return dest;
        }
    }
}
Here’s the unit test that tests how the mapping works

        [TestMethod]
        public void CreateMap_BetweenVulnerabilityAggregates_MapIsCreated()
        {
            Ccp.Infrastructure.Mappings.Initialize();

            Ccp.Entities.VulnerabilityAggregate source = CreateVulnerabilityAggregate();
            Ccp.Entities.TropicalCyclone.VulnerabilityAggregate destination = Mapper.Map<Ccp.Entities.VulnerabilityAggregate, Ccp.Entities.TropicalCyclone.VulnerabilityAggregate>(source);

            Assert.AreNotEqual<int>(source.Id, destination.Id); // because ignored in mapping
            Assert.AreEqual<string>(source.BuildingQuality, destination.BuildingQuality);
            Assert.AreEqual<int>(source.VulnerabilityFunctionId.Value, destination.VfId.Value);
        }