Function returns Entity or DTO
I am working on a project that deals WCF services. In our design we separated Entities and Datacontracts (DTO). The application layer takes care of converting Entities to DTO’s before passing it to Service layer. In the application layer, classes communicates and passes data but I need the inter application layer communication should deals with Entities not DTO’s. So I wanted to find a way so that the function can return Entity or DTO. In this post I will explain how I achieved it, It’s pretty simple.
One option is I could have moved the Entity to DTO mapping to Service layer. I decided not to do it and want to make the service layer light weight.
Another option is shown below.
Let’s take an example of POS system and here we deals with Product. For simplicity I takeout the Interface.
public class ProductMaintenance { private Product _currentlyFetchedProduct; public ProductMaintenance Get(string productCode) { //do the logic to fetch product. return this; } public Product ToEntity() { return _currentlyFetchedProduct; } public ProductDTO ToDTO() { //do the logic to map Entity to DTO return new ProductDTO(); } }
The Service class will make a call to the ProductMaintenance as shown below
ProductMaintenance productMaintenance = new ProductMaintenance(); return productMaintenance.GetProduct(productCode).ToDTO();
What if the ProductMaintenance class returns more than one type of Data, say it returns Product and List of Product. Then the complexity increases and difficult to handle it.
I introduced a new class to handle this situation called DataGetter, see the code below.
interface IDataGetter<TSource, TDest> where TSource : class where TDest : class { TDest ToDTO(); TSource ToEntity(); }
public class DataGetter<TSource, TDest> : IDataGetter<TSource,TDest> where TSource:class where TDest:class { private TSource _entity; public DataGetter(TSource entity) { this._entity = entity; } public TSource ToEntity() { return _entity; } public TDest ToDTO() { //Do the logic to convert entity to DTO return null; } }
Let’s rewrite the ProductMaintenance class with the new DataGetter.
public IDataGetter<Product, ProductDTO> GetProduct(string productCode) { Product productFetched = Repository.GetProduct(productCode); return new DataGetter<Product, ProductDTO>(productFetched); } public IDataGetter<IList<Product>, IList<ProductDTO>> GetAll() { IList<Product> products = Repository.GetAllProducts(); return new DataGetter<IList<Product>, IList<ProductDTO>>(products); }
The service can call the ProductMaintenance as shown below.
public ProductDTO GetProduct(string productCode) { ProductMaintenance productMaintenance = new ProductMaintenance(); return productMaintenance.GetProduct(productCode).ToDTO(); } public IList<ProductDTO> GetAllProducts() { ProductMaintenance productMaintenance = new ProductMaintenance(); return productMaintenance.GetAll().ToDTO(); }
How to call ProductMaintenance from the same layer, that time we need to deal with Entity instead of DTO. We can easily do that by calling the same function chain with ToEntity() as shown below.
ProductMaintenance productMaintenance = new ProductMaintenance(); return productMaintenance.GetAll().ToEntity();
Another advantage of DataGetter is, we can abstract the Entity to DTO mapping from the application class. So any changes to the mapping provider can be done in a single place. For Entity mapping I use AutoMapper.
Word of Caution
If we are using any ORM with Lazy loading then make sure the repository session is opened till ToDTO or ToEntity call completes. Say for e.g. if we create the session in GetProduct and close the session in the finally, then ToDTO or ToEntity will throw error as the session is closed and unable to do Lazy loading. I use Castle Windsor to inject the repository dependencies and the session will get closed only in the Dispose function.
The purpose is still not clear. Entities should be converted to DTO only when dealing with Services. The application wide entities should be used. But I prefer to have another set of objects, generally known as Domain Object or business object. Entities are reflection of database, the domain objects are application objects which are hydrated (populated) by Entities. There will be over head of translation, but code is maintainable.
The solution what you have provided is good. Even extension methods are handy in such cases.
Premanshu
February 21, 2013 at 12:54 am
Hi Premanshu,
Thanks for leaving your comments. Here entities is not just a db representation its actually domain model, that has logic. Here I am talking about DDD, not transactional scripting.
Regards,
Sony Arouje
Sony Arouje
February 21, 2013 at 9:49 am