A Useful Entity Translator Pattern / Object Mapper Template
In this post I’m going to cover the Entity Translator pattern and provide a useful base class for implementing this pattern in your application.
The ‘Entity Translator Pattern’ (defined here and here) covers situations where you need to move object state from one object type to another and there are very strict reasons why these object types are not linked or share inheritance hierarchies.
There are many occasions when you need to convert a set of data from one data type to another. Where you are using DTOs (Data Transport Objects) for example, which serve the purpose of being light and easy to pass between the layers of your application but will often end up needing to be converted in some way into a Business Model or Domain Object. The use of Data Contract objects in WCF (Windows Communication Foundation) is a common example of a where you need this translation from DTOs to Business Model objects, and the Entity Translator pattern is a good fit. After carefully layering your application design into loosely coupled layers you often don’t want WCF created types, or entity objects generated from an ORM tool (Object Relational Mapper) leaking out of their respective layers. Also you may have a requirement to use a ViewModel object pattern requiring state transfer from the ViewModel to the master model object etc. All of these examples have in common the problem of how do you get the state from object A into object B where the two objects are of a different type.
Now of course the most simplistic method would be to hand crank the conversion by hand at the point you need it to. For example:
1
2
3
4
5
CustomerDTO dto;
Customer customer;
dto.Name = customer.Name;
dto.Id = customert.Id;
Whilst this approach is acceptable it means writing potentially a lot of code and can lack structure in its use. Other developers working in your team may end up repeating your code elsewhere. Additionally there may be a lack of separation of concerns if this translation code sits with the bulk of your logic making unit testing more complex.
An alternative (keyboard friendly) approach to the problem is to use a tool that can automate the translation of values from one object to another such as AutoMapper. For an example of how to use AutoMapper check out this post and this post, oh and this one. AutoMapper can automatically (through reflection) scan the source object and target object and copy the property values from one to the other (so dto.Name is automatically copied to customer.Name). This works painlessly where the property names match but if they don’t then some mapping has to be configured. The advantage of this approach is that it can save a lot of code having to be written and tested. The downside is performance and less readability of your mapping code. If you have a lot of mapping code to write and you have control over both object structures under translation then this can be a very productive approach.
Of course there is always a middle ground where you want to add some structure to your translation code, perhaps need the performance of specific ‘object to object’ coding or have complex translation logic. For these situations consider the following implementation, courtesy of Microsoft Patterns & Practices .
Microsoft’s Smart Client Software Factory includes an Entity Translator service in it’s Infrastructure.Library project which enables you to write custom translators and then register these with the Entity Translator service. It provides two base classes: ‘EntityMapperTranslator’ and ‘BaseTranslator’. BaseTranslator class implements the an ‘IEntityTranslator’.
BaseTranslator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public abstract class BaseTranslator : IEntityTranslator
{
public abstract bool CanTranslate(Type targetType, Type sourceType);
public bool CanTranslate<TTarget, TSource>()
{
return CanTranslate(typeof(TTarget), typeof(TSource));
}
public TTarget Translate<TTarget>(IEntityTranslatorService service, object source)
{
return (TTarget)Translate(service, typeof(TTarget), source);
}
public abstract object Translate(IEntityTranslatorService service, Type targetType, object source);
}
EntityMapperTranslator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public abstract class EntityMapperTranslator<TBusinessEntity, TServiceEntity> : BaseTranslator
{
public override bool CanTranslate(Type targetType, Type sourceType)
{
return (targetType == typeof(TBusinessEntity) && sourceType == typeof(TServiceEntity)) ||
(targetType == typeof(TServiceEntity) && sourceType == typeof(TBusinessEntity));
}
public override object Translate(IEntityTranslatorService service, Type targetType, object source)
{
if (targetType == typeof(TBusinessEntity))
return ServiceToBusiness(service, (TServiceEntity)source);
if (targetType == typeof(TServiceEntity))
return BusinessToService(service, (TBusinessEntity)source);
throw new EntityTranslatorException();
}
protected abstract TServiceEntity BusinessToService(IEntityTranslatorService service, TBusinessEntity value);
protected abstract TBusinessEntity ServiceToBusiness(IEntityTranslatorService service, TServiceEntity value);
}
If we wanted to use this as a general template for entity translation in a non SCSF solution then we can remove the detail around IEntityTranslator services assuming that we’re not building a translator service but purely writing individual translators. Our classes then look more like this:
BaseTranslator:
1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class BaseTranslator
{
public abstract bool CanTranslate(Type targetType, Type sourceType);
public bool CanTranslate<TTarget, TSource>()
{
return CanTranslate(typeof(TTarget), typeof(TSource));
}
public abstract object Translate(Type targetType, object source);
}
EntityMapperTranslator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public abstract class EntityMapperTranslator<TBusinessEntity, TServiceEntity> : BaseTranslator
{
public override bool CanTranslate(Type targetType, Type sourceType)
{
return (targetType == typeof(TBusinessEntity) && sourceType == typeof(TServiceEntity)) ||
(targetType == typeof(TServiceEntity) && sourceType == typeof(TBusinessEntity));
}
public TTarget Translate<TTarget>(object source)
{
return (TTarget)Translate(typeof(TTarget), source);
}
public override object Translate(Type targetType, object source)
{
if (targetType == typeof(TBusinessEntity))
{
return ServiceToBusiness((TServiceEntity)source);
}
if (targetType == typeof(TServiceEntity))
{
return BusinessToService((TBusinessEntity)source);
}
throw new System.ArgumentException("Invalid type passed to Translator", "targetType");
}
protected abstract TServiceEntity BusinessToService(TBusinessEntity value);
protected abstract TBusinessEntity ServiceToBusiness(TServiceEntity value);
}
We could refactor this further by removing the BaseTranslator class completely and just use the EntityMapperTranslator as the base class for our translators. The BaseTranslator class it stands above does provide some benefit if we can foresee circumstances where we want to follow a standard translation pattern for more than just entity translation. We could create a DataMapperTranslator, for example, that would derive from BaseTranslator and would differ the entity translation specifics of the EntityMapperTranslator implementation. Removing the BaseTranslator class, however, results an in EntityMapperTranslator class like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public abstract class EntityMapperTranslator<TBusinessEntity, TServiceEntity>
{
public bool CanTranslate(Type targetType, Type sourceType)
{
return (targetType == typeof(TBusinessEntity) && sourceType == typeof(TServiceEntity)) ||
(targetType == typeof(TServiceEntity) && sourceType == typeof(TBusinessEntity));
}
public TTarget Translate<TTarget>(object source)
{
return (TTarget)Translate(typeof(TTarget), source);
}
public object Translate(Type targetType, object source)
{
if (targetType == typeof(TBusinessEntity))
{
return ServiceToBusiness((TServiceEntity)source);
}
if (targetType == typeof(TServiceEntity))
{
return BusinessToService((TBusinessEntity)source);
}
throw new System.ArgumentException("Invalid type passed to Translator", "targetType");
}
protected abstract TServiceEntity BusinessToService(TBusinessEntity value);
protected abstract TBusinessEntity ServiceToBusiness(TServiceEntity value);
}
This is now a neat and simple template from which we can code our custom translators. Now for translating from CustomerDTO to Customer we can create a translator that derives from EntityMapperTranslator and we only need to code the two translate methods (one for translating CustomerDTO to Customer and vice versa).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CustomerTranslator : EntityMapperTranslator<BusinessModel.Customer, DataContract.CustomerDTO>
{
protected override DataContract.CustomerDTO BusinessToService(BusinessModel.Customer value)
{
DataContract.CustomerDTO customerDTO = new DataContract.CustomerDTO();
customerDTO.Id = value.Id;
customerDTO.Name = value.Name ;
customerDTO.PostCode = value.PostCode;
return customerDTO;
}
protected override BusinessModel.Customer ServiceToBusiness(DataContract.CustomerDTO value)
{
BusinessModel.Customer customer = new BusinessModel.Customer();
customer.Id = value.Id;
customer.Name = value.Name ;
customer.PostCode = value.PostCode;
return customer;
}
}
This is just a simple example of course as the translation logic could get quite complex. Also don’t forget that the translator classes could also make use of some of the automated tools described earlier such as AutoMapper. Calling AutoMapper inside a translator would enable you to easily combine both manual and automated translation code enabling you to save on tedious typing (and those dreaded copy and paste errors) but gives a simple structure to your manual translation logic where this approach is preferable. Either way by creating custom translators we have encapsulated all of our translation code into separate reusable and testable classes, that all share a developer friendly common interface.
In summary then, we’ve covered using a simple Entity Translation template, based on Microsoft’s Smart Client Software Factory offering and shown how it can be used in your application for adding structure to your object mapping/translation code.
Additional Useful Links:
http://code.google.com/p/translation-tester/
http://icoder.wordpress.com/category/uncategorized/
http://c2.com/cgi/wiki?TranslatorPattern