I've been reading through StackOverflow posts regarding converting a DTO's entityID to a Domain's entity using NHibernate and AutoMapper. There's certainly a lot of information out there on it, but everyone seems to have a different suggestion, many of which suggest using a different tool altogether (ValueInjecter). Furthermore, a lot of the information I have found is dated several years. As such, I'm addressing this question again in hopes of clearing things up for me.
I have the following DTO class:
public class PlaylistDto
{
public Guid Id { get; set;
public Guid StreamId { get; set; }
public List<PlaylistItemDto> Items { get; set; }
}
and a corresponding Domain:
public class Playlist
{
public Guid Id { get; set;
public Stream Stream { get; set; }
// Use interfaces so NHibernate can inject with its own collection implementation.
public IList<PlaylistItem> Items { get; set; }
}
To start, I declare my intent to map these two entities to each other:
Mapper.CreateMap<Playlist, PlaylistDto>().ReverseMap();
Mapper.CreateMap<PlaylistItem, PlaylistItemDto>().ReverseMap();
Mapper.CreateMap<Stream, StreamDto>().ReverseMap();
ReverseMap allows me to easily declare two-way mappings.
At this point, I am able to successfully convert a Playlist to a PlaylistDto without much effort:
// Singular:
PlaylistDto playlistDto = Mapper.Map<Playlist, PlaylistDto>(playlist);
// Collection:
List<PlaylistDto> playlistDtos = Mapper.Map<List<Playlist>, List<PlaylistDto>>(playlists);
This works great. No extra code is needed. However, problems arise when I attempt to map the other direction.
A playlistDto only stores an ID reference to its Stream. If I convert the DTO to a domain, like so:
Playlist playlist = Mapper.Map<PlaylistDto, Playlist>(playlistDto);
Then playlist's Stream is always null regardless of playlistDto's StreamID.
I would like to add an intermediary step which allows the Domain's entity to be fetched via NHibernate using the Dto's entityId.
I was not using AutoMapper, I would achieve this via:
playlist.Stream = StreamDao.Get(playlistDto.StreamId);
With that said, I have questions:
- What is the agreed upon simplest method for achieving this using AutoMapper?
- Is ValueInjecter truly a choice I should be considering here? Am I going down a path of forcing AutoMapper to do things which will lead to headaches?
- If ValueInjecter is preferred... is it still maintained? The project looks extremely dated. In addition, I saw mentions that ValueInjecter does not support collections. This would be a huge turn-off if this is the case.
A few examples I have seen which potentially solve my issue:
Using AutoMapper to unflatten a DTO:
Mapper.CreateMap<Person, Domain.Person>()
.ForMember(dest => dest.Address, opt => opt.ResolveUsing( src => { return new Address() {Address1 = src.Address, City = src.City, State = src.State }; }))
AutoMapper map IdPost to Post:
public class Id2EntityConverter<TEntity> : ITypeConverter<int, TEntity> where TEntity : EntityBase
{
public Id2EntityConverter()
{
Repository = ObjectFactory.GetInstance<Repository<TEntity>>();
}
private IRepository<TEntity> Repository { get; set; }
public TEntity ConvertToEntity(int id)
{
var toReturn = Repository.Get(id);
return toReturn;
}
#region Implementation of ITypeConverter<int,TEntity>
public TEntity Convert(ResolutionContext context)
{
return ConvertToEntity((int)context.SourceValue);
}
#endregion
}
(there's more to this, but this is the gist of it)
Advice appreciated. Thanks!