Home > front end >  Pass mapper as type and use methods on generic type
Pass mapper as type and use methods on generic type

Time:09-22

So I've created a base repository class which returns domain models and uses entity objects to manipulate data in the database. Here is the repository class:

public abstract class Repository<TDomain, TEntity, TMapper> : IReadWriteRepository<TDomain>
    where TDomain : Model
    where TEntity : Entity
    where TMapper : IMapper<TDomain, TEntity>
{
    private readonly ApplicationDbContext _context;

    public Repository(ApplicationDbContext context)
    {
        _context = context;
    }

    public IQueryable<TDomain> Get()
    {
        var entities = _context.Set<TEntity>();
        // Return domain models
    }

    public void Add(TDomain item)
    {
        // Convert to entity model
        _context.Set<TEntity>().Add(item);
    }

    public void Update(TDomain item)
    {
        // Convert domain to entity model
        var entry = _context.Entry<TEntity>(entity);

        if (entry.State == EntityState.Detached)
        {
            _context.Set<TEntity>().Attach(entity);
            entry.State = EntityState.Modified;
        }
    }

    public void Delete(int id)
    {
        var entity = _context.Set<TEntity>().Find(id);
        _context.Set<TEntity>().Remove(entity);
    }
}

As you can see at this point I'm struggling to convert the entity objects to domain and vice versa.

I have defined an IMapper interface which when implemented will convert entity into domain and vice versa.

public interface IMapper<TDomain, TEntity> where TDomain : Model where TEntity : Entity
{
    public TDomain ToDomain(TEntity entity);
    public TEntity ToEntity(TDomain domain);
}

Problem:

I can't seem to use any of these methods in the Repository base class through TMapper, I basically want to be able to just have 1 simple Repository implementation which performs all CRUD operations but using multiple Mappers to assist with mapping objects.

CodePudding user response:

You cannot call methods just using a generic type, you need an actual object, and such an object would typically be injected in the constructor:

public Repository(ApplicationDbContext context, TMapper mapper)
{
    _context = context;
    _mapper = mapper;
}

Note that there is no real advantage making the mapper generic, you could just inject a IMapper<TDomain, TEntity> instead. If you are using a DI container you would need to register a mapper for each TDomain/TEntity-pair. Different DI containers might work differently, but I would expect that if you resolve Repository<MyDomain, MyEntity> the container should look for IMapper<MyDomain, MyEntity>, and if you registered an implementation for that interface it should all work out.

You might however consider using the visitor pattern instead. This would allow you to create a single class that take care of converting all entities to domain objects, or vice versa. I tend to like this method since the compiler can force you to add any missing mappings when you add new types.

  • Related