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.