Custom Auto Entity Mapper

So the other day in the current project I am working on, we were tasked with coming up with a mapping tool that would automatically map a View model or DTO to an entity and reverse. This was a pretty neat idea, so I took it on myself because I love learning new things about Generics, reflection and the like. So here went nothing Smile.

 

So the first thing I needed to do was create a class that will take in two objects of dynamic type. For those of you that don’t know, a dynamic type allows a developer to pass in any object (with some constraints) and the code and compiler know how to handle it at run time. A common built in Generic object that takes in a dynamic type is List<T>. This object has many methods attached to it that makes adding and looping through a list very easy. The T in this case is any C# object that inherits from at the very least object and allows you to make a list of those objects. This is great for making helpers that you want to create for your libraries to work across many object types complex or primitive.

So here is the definition of the class

public class ObjectMapper<T, F> where T : class where F : class

 

So what does all this mean? Well, first we are creating a class named ObjectMapper. This class is defining two type arguments T and F. The name of these types is arbitrary and can be anything, even a word that will help you remember what it references. The next piece is defining what T and F represent. The most common thing to use is where [Type] : class. This means that the Type can be anything that has a class. You can also replace class with an interface. This will limit the developers to only using classes that derive that interface. There are a few other constraints you can use if the requirement is there. that we will not go over here.

The first method we create is called the DataMapper.

/// <summary>

/// Data mapper. Maps the data from the first object to the 

/// second object

/// </summary>

/// <param name="objectToMap">The object to map.</param>

/// <param name="emptyObject">The empty object.</param>

/// <returns></returns>

/// <exception cref="System.NullReferenceException">One or more objects to map are null</exception>

/// <exception cref="System.Exception">The property count for these objects are not the same and cannot be mapped</exception>

public static object DataMapper(T objectToMap, F emptyObject)

{

    // Check nulls

    if (objectToMap == null || objectToMap == null)

        throw new NullReferenceException("One or more objects to map are null");

 

    var propertyArrayList = GetProperties(objectToMap, emptyObject);

 

    // Copy all the properties from object1 to object2

    var returnObject = MapProperties(propertyArrayList[0], propertyArrayList[1], objectToMap, emptyObject);

 

    return returnObject;

}

 

This method will take in two parameters. The first is the object you wish to map and the second is the empty object. This will become more clear after we show it being used.

The next two methods are private and will not be accessible outside of this class. The only thing that accesses these methods is the DataMapper() and each other.

/// <summary>
/// Gets the properties.
/// </summary>
/// <param name="objectToMap">The object to map.</param>
/// <param name="emptyObject">The empty object.</param>
/// <returns></returns>
/// <exception cref="System.NullReferenceException">One or more objects to map are null</exception>
/// <exception cref="System.Exception">The property count for these objects are not the same and cannot be mapped</exception>
private static List<PropertyInfo[]> GetProperties(T objectToMap, F emptyObject)
{
if (objectToMap == null || objectToMap == null)
throw new NullReferenceException("One or more objects to map are null");

List<PropertyInfo[]> propertyArrayList = new List<PropertyInfo[]>();

// Get all the properties of these objects
PropertyInfo[] propertiesObj1 = objectToMap.GetType().GetProperties();
PropertyInfo[] propertiesObj2 = emptyObject.GetType().GetProperties();

// Make sure that there are properties and
//that both objects have the same amount of properties
if ((propertiesObj1.Count() != propertiesObj2.Count()) || (propertiesObj1 == null || propertiesObj2 == null))
throw new Exception("The property count for these objects are not the same and cannot be mapped");

propertyArrayList.Add(propertiesObj1);
propertyArrayList.Add(propertiesObj2);

return propertyArrayList;
}

/// <summary>
/// Maps the properties.
/// </summary>
/// <param name="properties1">The properties1.</param>
/// <param name="properties2">The properties2.</param>
/// <param name="objectToMap">The object to map.</param>
/// <param name="emptyObject">The empty object.</param>
/// <returns></returns>
private static object MapProperties(PropertyInfo[] properties1, PropertyInfo[] properties2, T objectToMap, F emptyObject)
{
// Copy all the properties from object1 to object2
for (int propCounter = 0; propCounter < properties1.Count(); propCounter++)
{
var val = properties1[propCounter].GetValue(objectToMap,null);
properties2[propCounter].SetValue(emptyObject,val,null);
}
return emptyObject;
}

The first method uses reflection and gets all the properties in the object being mapped as well as all the properties in the empty object using object.GetType().GetProperties(). Even though the data in the empty object is empty of data, we want to make sure that the properties themselves will all match up. Remember this is for taking any object (like an entity) and copying it to an object that is similar (like a DTO). if any of the properties do not match up, we throw an exception. This probably could be a better exception (like Not Implemented), but I’ll digress.

The second method actually does the meat of the operation. This method (MapProperties) actually goes through and maps the properties from one to the other using SetValue() and returns the new object full of the new data goodness!

Now if you want use this awesomeness, how does one do this? Well, lets say that you have  two objects, one called PersonDTO and the other called PersonViewModel and they looked something like this:

 

public class PersonViewModel
{
public string First { get; set; }
public string Last { get; set; }
public int Age { get; set; }
}

 

public class PersonDTO
{

public string First { get; set; }
public string Last { get; set; }
public int Age { get; set; }
}

And now you want to take a PersonViewModel full of data and convert I to a PersonDTO. Normally, you would have to do a one for one mapping, but not with our new cool Mapper!!

 

try
{

PersonViewModel model = new PersonViewModel()
{
First = "Gregg",
Last = "Coleman",
Age = 31
};

PersonDTO dto = new PersonDTO();

var mappedObject = ObjectMapper<PersonViewModel, PersonDTO>.DataMapper(model, dto);
if (mappedObject == null)
MessageBox.Show("Object came back null");
else
MessageBox.Show((mappedObject as PersonDTO).First);
}

catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}

 

The above code should do the trick!

 

Hope everyone enjoyed!! Happy Coding Smile

About Gregg Coleman

I am Senior-level Software Engineer working primarily these days with .NET. I have a good working knowledge of ASP.NET MVC, Web Forms, WCF web services and Windows Services. I spend much of my time in the Web Services (SOAP and REST) world in my current job designing and implementing various SOA architectures. I have been in the software engineering industry for about 6 years now and will not now nor ever consider myself an "expert" in programming because there is always so much to learn. My favorite thing about designing software is there are always new emerging technologies and something to learn every day! My current job has me spending much of my job on the bleeding edge of technologies and changing gears all the time, so I'm never bored and always challenged. On my spare time I enjoy weight training, reading and venturing to new places near by. Of course programing and learning new technologies are another hobby of mine.
This entry was posted in .NET, .NET 4.5, ASP.NET, C#, Classes, Data Mapping, Generics, MVC, Namespaces and tagged , , , , , , , , . Bookmark the permalink.

Leave a comment