How to map a Domain model to a Presentation Model, can this be something?

If you have read my previous post about Presentation Model, I decided to try to see if I could make the mapping between the Presentation Model and the Domain Model simple by creating an Object to Object Mapper. I don’t want to use a messy XML file or attributes on the classes to handle the configuration of how object should be mapped to each other. Instead I wanted to use the nice Object Initializer feature in C# 3.0 which I think is easy to read and easy to use. Here is a modified version of my Mapping method I had in my CustomersController class in my previous post:

 

public PresentationCustomer CustomerToPresentationCustomer(Customer customer)
{
   return new PresentationCustomer()
              {
                   CustomerID = customer.ID,
                   FirstName = customer.FirstName,
                   Lastname = customer.Lastname,
                   CompanyName = customer.CompanyName
              };
}

 

The code above is easy to read, at least I think so. I can easy see that I map a Customer to a PresentationCustomer, and it's also easy to see the mapping of properties. Compare the above code with the following XML:

<mapping
      name="CustomerToPresentationCustomer"
      sourceType="MyApp.DomainLayer.Customer"
      destinationType="MyApp.PresentationLayer.PresentationCustomer">
      
      <map sourceField="ID" destinationField="CustomerID"/>
      <map sourceField="FirstName" destinationField="FirstName"/>
      <map sourceField="LastName" destinationField="LastName"/>
      <map sourceField="CompnayName" destinationField="CompanyName"/>

</mapping>

 

What do you think is easier to read? I think the part where  Property = Property, rather than <map sourceField="Property" destinationField="Property"/>.

To map two object with each other, I also need the type of the two objects. So either if I hard code the mapping like in the first example or use XML I need to specify the types. I also need to give the mapping configuration a name. In the XML file the name attribute of the <mapping> element specifies the name of the mapping. In the C# code, the name is specified as a method name. The source object is specified in the XML file by using the sourceType attribute, where the whole type is specified. In the C# code, the argument of the method is the source. The destination object (the object to map the source object with) also need to be specified. In XML, an attribute is used, and in the C# code as a return type. Then we need to  specify what field should be mapped to what field.

What I decided to do, is to reuse my mapping method written in C#, but I wanted to make sure I could do the mapping in a text file, so I don't need to recompile if I need to change the mapping in the future. I created a simple method to handle the execution of the mapping, and add it to my Infrastructure Layer. Here is how I now map my Customer to the PresentationCustomer:

 

DynamicMapper dynMap = new DynamicMapper();

var presentationCustomer = dynMap.Map<PresentationCustomer>(customer, "CustomerToPresentationCustomer");

 

The Map method is a generic method where I specify the type of the Destination class "PresentationCustomer", the method has two arguments, the source where I pass the Customer (the domain object), and the mapKey which is used to specify what mapping configuration I want to use.

My mapping file where I have my mapping configuration has the following content:

 

public PresentationCustomer CustomerToPresentationCustomer(Customer customer)
{
      return new PresentationCustomer()
                 {
                      CustomerID = customer.ID,
                      FirstName = customer.FirstName,
                      Lastname = customer.Lastname,
                      CompanyName = customer.CompanyName
                  };
 }

 

Plain C# 3.0 code. The mapKey passed to the Map method is the name of the method which should be executed and perform the mapping. I used Dynamic Compilation to compile the code and then execute it. Here is part of the code so you can see the structure of it:

 

public Destination Map<Destination>(object source, string mapKey)
{
      string mappingCode = this.ReadContentFromFile("...");

      Type sourceType = source.GetType();
      Type destinationType = typeof(Destination);

      CompilerParameters compilerParameters = this.SetupCompilerParameters(sourceType, destinationType);

      string sourceCode = CreateMappingClassSourceCode(mappingCode, sourceType, destinationType);

      var compiler = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
      CompilerResults compiledResult = compiler.CompileAssemblyFromSource(compilerParameters, sourceCode);

      if (compiledResult.Errors.HasErrors)
          throw new ApplicationException(CreateErrorMessage(compiledResult) + "\r\n\r\n" + sourceCode);

      return ExecuteMapping<Destination>(mapKey, source, compiledResult.CompiledAssembly);
 }

 

I'm not sure if I will use this in production yet, I need to do some testing and need to cache the compiled code while there aren't any changes to the mapping configuration file etc. By using Reflection I could easy add the namespace and assembly of the source and destination objects, no need to specify them in the mapping file.

private CompilerParameters SetupCompilerParameters(Type sourceType, Type destinationType) { CompilerParameters compilerParameters = new CompilerParameters(); compilerParameters.GenerateInMemory = false; compilerParameters.ReferencedAssemblies.Add("System.dll"); compilerParameters.ReferencedAssemblies.Add("System.Core.dll"); compilerParameters.ReferencedAssemblies.Add(sourceType.Assembly.ManifestModule.ScopeName); if (!compilerParameters.ReferencedAssemblies.Contains(destinationType.Assembly.ManifestModule.ScopeName)) compilerParameters.ReferencedAssemblies.Add(destinationType.Assembly.ManifestModule.ScopeName); return compilerParameters; }

7 Comments

  • Interesting solution. It would be good if you could incorporate some convention based mapping as well, for example automatically map properties with the same name. This would reduce the number of:
    presentationModel.PropertyX = domainModel.PropertyX
    presentationModel.PropertyY = domainModel.PropertyY
    etc

    Of course some mechanism to override this convention would be needed, there might be, depending on the domain model some dangerous in doing automatic property mapping but I think in most cases it should be relatively safe and will lessen the number of lines of code needed for the mapping which is good.

    But this only makes the mapping easier, you would still need to duplicate a lot of the domain model classes and properties (unless you would use inheritance).

  • Nice!

    You will need to cache the assembly, because a generated assembly will stay in memory during the complete life time of the AppDomain (this is differen't with LCG). I bet you'll bet an OutOfMemoryException with this in production.

  • I have been using for several years to build a Data Acees Layer library named bltoolkit (bltoolkit.com). It works very very fast because use Emit based code generation and has extensive mapping features (for .NET 2.0 also). But this is not ORM tool. See examples on site.
    With bltoolkit method CustomerToPresentationCustomer might look like:

    public PresentationCustomer CustomerToPresentationCustomer(Customer customer)
    {
    return Map.ObjectToObject(customer)
    }
    This is very similar to your decision, but Map in bltoolkit contains yet many useful methods for mapping, with the possibility of writing their extensions :)


  • svdeursen:
    Yes I know, I actually write that in the post "and need to cache the compiled code " maybe I used the wrong words when I wrote "compiled code", it was of course the assembly after the compilation and creation. But thanks verry much for the comment.. good information for other readers that want to do Dynamic Compliation.
    I was first thinking of setting the GenereateInMemory property to false


  • dkl:
    Actually it’s not a DTO, DTO is used to transfer a lot of data to reduce the number of method calls. What I do is to create a new model suite for the presentation layer. So it’s more or less the Presentation Model pattern that I use, only that my example code uses a simple object and only one object. You need to read my first post, this is only a follow up post only, I forgotten to link to my previous post. What I want to do is to not use any tools, or any XML file, you name it. I want to reuse the way to manually do the mapping, instead of manually create an XML file, I manually create simple C# code as a format of the configuration file. This is still only something I do for fun, and I should probably never use an object to object mapper, there is no reason to use it as long as I work with “hard” data. I still need to change code if there are changes to the model, and do a recompilation. A mapper is more suitable for “soft” data, a ORM is an example of such mapper.

  • You should check out Otis:

    http://code.google.com/p/otis-lib/

    Looks like you are taking a similar approach.

  • How would I do this if my source or taget class inherits from a base class? For example, my source class Person inherits from a base class which has an ID property, how would I map ID (which is coming from the base class) to my target?

Comments have been disabled for this content.