For simple entities and aggregates having a standard set of CRUD operations on your repository makes a lot of sense. However, for less standard aggregates and complicated operations it doesn't make sense to implement these common operations.
For example: Suppose before you want to add your student to the database, you need to make some complicated validation over that student and hide those details over the client.
Preferably, I like to use the DBContext directly. It gives me more free space to do whatever i need without thinking too much for adding that method to the interface, and go to implement it.
Anyway if you want to use Repository pattern. I recommend to use the generic one such as the following:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
private readonly CrudContext _context;
private readonly DbSet<TEntity> _dbSet;
public Repository(CrudContext context)
{
this._context = context;
this._dbSet = context.Set<TEntity>();
}
public IEnumerable<TEntity> List()
{
return _dbSet.ToList();
}
public TEntity GetById(int id)
{
return _dbSet.Find(id);
}
public void Insert(TEntity entity)
{
_dbSet.Add(entity);
_context.SaveChanges();
}
public void Update(TEntity entity)
{
_dbSet.Attach(entity);
_context.Entry(entity).State = EntityState.Modified;
_context.SaveChanges();
}
public void Delete(int id)
{
var entityToDelete = _dbSet.Find(id);
_dbSet.Remove(entityToDelete);
_context.SaveChanges();
}
}
If it comes to my preference, Either I would use the dbcontext directly inside the dependent class or I would create an Interface called IEntityInserter
and for each Record type or Model that has too much logic of inserting, I would create an implementation called
StudentBasedEntityInserter : IEntityInserter<Student> {
public void Insert(Student @student){}
}
and inject that IEntityInserter in any dependent class.
Finally, There is not right answers int that heated topic, some people would agree with my approach, others won't. Hope that it helps.