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;
}
}
}