Blog Stats
  • Posts - 62
  • Articles - 1
  • Comments - 35
  • Trackbacks - 76

 

Generic DTO Assembler

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;

}

 

}

}

 


Feedback

# re: Generic DTO Assembler

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. 8/5/2008 7:18 PM | Alvin Yong

Post a comment





 

Please add 6 and 8 and type the answer here:

 

 

Copyright © Mike Nichols