Geeks With Blogs
Mike Nichols - SonOfNun Technology If I were the captain on a big steamboat...
Playing around with incorporating Data Transfer Objects into my project, I figure I can use a touch of reflection to manage most assembler cases which are called from my service layer. May be a tad slower, but worth the savings for coding a million assembler classes. My base assembler has some basic methods for mapping simple properties to my entities suchas :

using System;

using System.Collections.Generic;

using System.Text;

using Cei.eMerge.Core.Domain;

using Cei.eMerge.Core.DaoInterfaces;

using Cei.eMerge.DTO;

using Cei.eMerge.Data;

using Cei.eMerge.Data.NHibernate;

using System.Reflection;

namespace Cei.eMerge.DomainFacade.Assemblers

{

internal abstract class DTOAssemblerBase

{

public DTOAssemblerBase() { }

private IDaoFactory _daoFactory;

/// <summary>

/// Wires up factory to NHibernate Dao strategy for hydration of objects. This can be

/// changed later to be a different provider.

/// </summary>

public IDaoFactory DaoFactory

{

get

{

if (_daoFactory == null)

{

_daoFactory = new NHibernateDaoFactory();

}

return _daoFactory;

}

}

protected virtual void MapEntityToDto<TEntity>(TEntity entity,DTOBase dto) where TEntity:DomainEntityBase

{

PropertyInfo[] props = dto.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);

foreach (PropertyInfo info in props)

{

PropertyInfo entityProp = entity.GetType().GetProperty(info.Name);

if (entityProp != null)

{

info.SetValue(dto, entityProp.GetValue(entity, null),null);

}

}

 

}

protected virtual void MapDtoToEntity<TEntity>(TEntity entity, DTOBase dto) where TEntity : DomainEntityBase

{

PropertyInfo[] props = entity.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);

foreach (PropertyInfo info in props)

{

if (!info.Name.Equals("Id"))

{

PropertyInfo dtoProp = dto.GetType().GetProperty(info.Name);

if (dtoProp != null)

{

info.SetValue(entity, dtoProp.GetValue(dto, null), null);

}

}

}

 

}

 

protected virtual void Validate()

{

 

 

}

}

}

 

And then my GenericAssembler to call from my service object is:

using System;

using System.Collections.Generic;

using System.Text;

using Cei.eMerge.Core.Domain;

using Cei.eMerge.DTO;

using Cei.eMerge.Core.DaoInterfaces;

using Cei.eMerge.Data;

using Cei.NHibernateCore;

using System.Reflection;

namespace Cei.eMerge.DomainFacade.Assemblers

{

/// <summary>

/// Assembler for generic fetching of entities and their corresponding DTO's.

/// Read-only access to entities is only permitted here, so any SaveOrUpdate commands

/// must be executed outside this object.

/// </summary>

/// <remarks>

/// This operates assuming the following conventions:

/// <list type="bullet">

/// <item>DTO property names are exactly (case-sensitive) matching the Domain Entity property names.</item>

/// <item>The target entity has a corresponding DAO method registered in teh IDaoFactory as

/// <b>Get<i>className</i>Dao</b></item>

/// </list>

/// </remarks>

/// <typeparam name="TEntity"></typeparam>

/// <typeparam name="TDto"></typeparam>

internal class GenericAssembler<TEntity,TDto> : DTOAssemblerBase where TEntity:DomainEntityBase,new()

where TDto:DTOBase,new()

{

internal GenericAssembler() { }

public TDto GetDTO(TEntity entity)

{

TDto dto = new TDto();

MapEntityToDto<TEntity>(entity, dto);

return dto;

}

/// <summary>

/// Mock service locator using reflection. Since naming conventions are assumed (GetEntityDao()) we

/// can safely avoid a formal configuration framework for this...AH RUBY!

/// </summary>

/// <returns></returns>

private MethodInfo GetDaoMethod()

{

string typeName = typeof(TEntity).UnderlyingSystemType.Name;

string getMethod = "Get" + typeName + "Dao";

MethodInfo method = DaoFactory.GetType().GetMethod(getMethod);

if(method!=null)

{

return method;

}

string MISSING_DAO =

"A Dao corresponding to {0} (a method named '{1}') could not be found.";

throw InvalidOperationException(string.Format(MISSING_DAO,typeName,getMethod));

}

public TEntity CreateEntity(TDto dto)

{

MethodInfo method = GetDaoMethod();

IDaoBase<TEntity, int> dao = (IDaoBase<TEntity, int>)method.Invoke(DaoFactory, null);

TEntity entity = new TEntity();

MapDtoToEntity<TEntity>(entity, dto);

return entity;

}

public TEntity UpdateEntity(int id, TDto dto)

{

MethodInfo method = GetDaoMethod();

IDaoBase<TEntity, int> dao = (IDaoBase<TEntity, int>)method.Invoke(DaoFactory, null);

TEntity entity = dao.GetById(id, true);

MapDtoToEntity<TEntity>(entity, dto);

return entity;

}

 

}

}

 

Posted on Tuesday, June 27, 2006 4:27 PM OOP, Patterns, Architecture | Back to top


Comments on this post: Generic DTO Assembler

# re: Generic DTO Assembler
Requesting Gravatar...
This idea is interesting. I have been investigating using LINQ in an n-tiered application and after deciding on using assemblers and DTOs, I found myself constructing a myriad of assemblers. I've been pondering using reflection to do this and having seen your implementation, I'll give it a try.

Thank you for sharing this.
Left by Alvin Yong on Aug 05, 2008 7:18 PM

# re: Generic DTO Assembler
Requesting Gravatar...
As I understand the Data Transfer Object (401) pattern, a DTO does not correspond to an entity, but rather to a given Remote Facade (388), typically in the context of a Service Layer (133). The goal of the DTO pattern is not to create a proxy Domain Model (116), but rather to simplify service method calls into the business layer. It is not necessary to code assembler classes for every single entity. An assembler class needs to be created only to express the mapping between the domain model and a specific set of fields (a DTO) needed for the interaction with the presentation layer.
Left by Scott Taylor on Jul 21, 2010 10:10 AM

Your comment:
 (will show your gravatar)
 


Copyright © Mike Nichols | Powered by: GeeksWithBlogs.net | Join free