Fun with Generics – From Repository to DTO

Oren posted a pattern for converting Domain entities to DTO’s using a delegate. He made a comment in his post:  “I did try to make it into a framework, but even I can’t make it more complex than this.”

I started laughing to myself because I actually tried something similar a few weeks ago, and was going to post, but I didn’t cuz I’m fairly new to this blog stuff and I wussed out… Time to be bold I suppose.

The project I am working on now has a large Service Layer on top of Repositories. You can only write so many services with translation before you start to see the commonalities and look for a way to abstract and reuse. (framework)

So, I thought I’d geek out and get carried away with some Fowler P of EEA. Basically, what I wanted to do is *try* and put some standardization to a Service Layer,  which returns DTO’s, which are assembled from a Domain Model, which are accessed from Repository. So DTO <-> Service Layer <-> Assembler <-> Repository <-> Domain Model.  Sweet. I am going to use the classic Fowler Album and Artist.

 

Abstractions

The Repository interface:

public interface IRepository<TDomainEntity>
{
   IEnumerable<TDomainEntity> Find(Func<TDomainEntity, bool> filter);
   TDomainEntity GetById(long Id);
   void Add(TDomainEntity domainEntity);
   void Delete(TDomainEntity domainEntity);
   void Update(TDomainEntity domainEntity);
}

The abstract Assembler:

public abstract class Assembler<TDto, TDomainEntity>
{
   public abstract TDomainEntity DtoToDomainEntity(TDto dto);
   public abstract TDto DomainEntityToDto(TDomainEntity domainEntity);
 
   public List<TDto> DomainEntitiesToDtos(IEnumerable<TDomainEntity> domainEntityList)
   {
       List<TDto> dtos = Activator.CreateInstance<List<TDto>>();
       foreach (TDomainEntity domainEntity in domainEntityList)
       {
           dtos.Add(DomainEntityToDto(domainEntity));
       }
       return dtos;
   }
 
   public List<TDomainEntity> DtosToDomainEntities(IEnumerable<TDto> dtoList)
   {
       List<TDomainEntity> domainEntities = Activator.CreateInstance<List<TDomainEntity>>();
       foreach (TDto dto in dtoList)
       {
           domainEntities.Add(DtoToDomainEntity(dto));
       }
       return domainEntities;
   }
}

And a base Service:

public class Service<TDto, TDomainEntity>
{
   Assembler<TDto, TDomainEntity> _assembler;
   IRepository<TDomainEntity> _repository;
 
   public Service(Assembler<TDto, TDomainEntity> assembler,
       IRepository<TDomainEntity> repository)
   {
       _assembler = assembler;
       _repository = repository;
   }
 
   public Assembler<TDto, TDomainEntity> Assembler { get { return _assembler; } }
   public IRepository<TDomainEntity> Repository { get { return _repository; } }
 
   public virtual List<TDto> Find(Func<TDomainEntity, bool> filter)
   {
       return _assembler.DomainEntitiesToDtos(_repository.Find(filter));
   }
 
   public virtual TDto GetById(long Id)
   {
       return _assembler.DomainEntityToDto(_repository.GetById(Id));
   }
 
   public virtual void Add(TDto dto)
   {
       _repository.Add(_assembler.DtoToDomainEntity(dto));
   }
 
   public virtual void Update(TDto dto)
   {
       _repository.Update(_assembler.DtoToDomainEntity(dto));
   }
 
   public virtual void Delete(TDto dto)
   {
       _repository.Delete(_assembler.DtoToDomainEntity(dto));
   }
}

Implementations

Now that I have some structure down, I think hammering out the implementations should go fast. I have more or less templated how the objects should interact.

The Domain Entities:

public class Artist
{
   public string Name { get; set; }
}
 
public class Album
{
   public long Id { get; set; }
   public string Title { get; set; }
   public Artist Artist { get; set; }
}

The DTO:

public class AlbumDto
{
   public long Id { get; set; }
   public string ArtistName { get; set; }
   public string Title { get; set; }
}

The Repository: (With some hacked data in a List)

public class AlbumRepository : IRepository<Album>
{
   #region IRepository<Album> Members
   List<Album> _albums = new List<Album>
   {
       new Album {Id=1, Title="Rock Out", Artist=new Artist{Name="Rock Dudes"}},
       new Album {Id=2, Title="Rock On", Artist=new Artist{Name="Rock Dudes"}},
       new Album {Id=3, Title="Yee haw", Artist=new Artist{Name="The Hicks"}}
   };
 
   public IEnumerable<Album> Find(Func<Album, bool> filter)
   {
       return _albums.Where(filter);
   }
 
   public Album GetById(long Id)
   {
       return _albums.Find(a => a.Id == Id);
   }
 
   public void Add(Album domainEntity)
   {
       _albums.Add(domainEntity);
   }
 
   public void Delete(Album domainEntity)
   {
       _albums.Remove(domainEntity);
   }
 
   public void Update(Album domainEntity)
   {
       Album album = _albums.Find(a => a.Id == domainEntity.Id);
       _albums.Remove(album);
       _albums.Add(domainEntity);
   }
 
   #endregion
}
The trusty Assembler:
public class AlbumAssembler : Assembler<AlbumDto, Album>
{
   public override AlbumDto DomainEntityToDto(Album domainEntity)
   {
       return new AlbumDto
       {
           Id = domainEntity.Id,
           ArtistName = domainEntity.Artist.Name,
           Title = domainEntity.Title
       };
   }
 
   public override Album DtoToDomainEntity(AlbumDto dto)
   {
       Album album = new Album { Id = dto.Id, Title = dto.Title };
       album.Artist = new Artist { Name = dto.ArtistName };
 
       return album;
   }
}

And of course the Service: (Super easy now)

public class AlbumService : Service<AlbumDto, Album>
{
   public AlbumService()
       : base(new AlbumAssembler(), new AlbumRepository()) { }
 
   public AlbumDto FindByAlbumTitle(string title)
   {
       return Find(a => a.Title == title).First<AlbumDto>();
   }
}

I went ahead and added another method using Find, but its nice to see all the standard interactions already there. If I need to extend the Service I can as all the methods defined are virtual and the Repository and Assembler are exposed as properties:

image

 

So there it is. I am not sure how I quite feel about it yet. I have a side project going and I think Ill try it out and see how it goes. It was certainly fun to do, and I’m definitely interested in your thoughts.

Though I posted all the code, you can find it here if your interested.

 

 

 

6 thoughts on “Fun with Generics – From Repository to DTO

  1. How about in your abstract assembler doing the following?

    public IEnumerable DomainEntitiesToDtos(IEnumerable domainEntityList)
    {
    foreach (TDomainEntity domainEntity in domainEntityList)
    {
    yield return DomainEntityToDto(domainEntity);
    }
    }

    public IEnumerable DtosToDomainEntities(IEnumerable dtoList)
    {
    foreach (TDto dto in dtoList)
    {
    yield return DtoToDomainEntity(dto);
    }
    }

  2. I dig it. Much cleaner. I was initially thinking I would want list functionality returned from the assembler to the service, but that is really not a concern of the assembler. Could always do a new List in the service if ever needed (actually cant think of a good reason), defer it to the latest possible moment.

    Thanks for the suggestion!

Comments are closed.

Find me

RSS
Facebook
Twitter
LinkedIn

Disclaimer

The opinions and content expressed here are my own and not those of my employer.