0
votes

I would like to implement simple IGenericRepository and IUnitOfWork interfaces in my application but I'm not sure whats the best way to do it.

As far as I could understand, UnitOfWork should be used for writing, while Repository should be used for reading. I have encountered one architecture and I really like it, but I only found interfaces and not the implementations, and I'm not sure how should I implement those.

public interface IGenericRepository : IDisposable
{
    IUnitOfWork CreateUnitOfWork();
    T FirstOrDefault<T>(Expression<Func<T, bool>> predicate) where T : class, IBaseEntity;
    IQueryable<T> Get<T>(Expression<Func<T, bool>> predicate = null, Func<IQueryable<T>, IOrderedQueryable<T>> sorter = null, params string[] includeProperties) where T : class, IBaseEntity;
    IQueryable<T> GetAll<T>() where T : class, IBaseEntity;
    IDbContext GetDbContext();
}

public interface IUnitOfWork : IDisposable
{
    int Commit();
    bool Delete<T>(T entity) where T : class, IBaseEntity;
    int DeleteItems<T>(IList<T> entities) where T : class, IBaseEntity;
    bool Insert<T>(T entity) where T : class, IBaseEntity;
    int InsertItems<T>(IList<T> entities) where T : class, IBaseEntity;
    bool Update<T>(T entity) where T : class, IBaseEntity;
    int UpdateItems<T>(IList<T> entities) where T : class, IBaseEntity;
}

I'm not sure how should those work. Should I use IDbContextFactory within repository to share DbContext between Repository and UnitOfWork or they should have separate DbContexts? If I implement UnitOfWork for write and Repository for read, should there be UnitOfWorks DbContext for write and Repositorys DbContext for read or they should share same DbContext?

I would really appreciate good explanation of how DbContext and UnitOfWork/Repository should work.

Those would be implemented in service in such way:

public CustomerService(IGenericRepository repository)
{
    this.repository = repository;
    this.context = this.repository.GetDbContext();
}

public void UpdateCustomer(Customer customer)
{
    var uow = this.repository.CreateUnitOfWork();
    uow.AddForSave(customer);
    uow.Commit();
}

public List<Customer> GetAll()
{
    return this.repository.GetAll<Customer>();
}

Any help, explanation about DbContext and UoW/Repository relation, or good tutorial similar to this implementation would help.

Regards.

1
UnitOfWork should be used for writing, while Repository should be used for reading I've never heard of thatJonesopolis
Not should as "must", but is advised for many entity update (single entity can be updated with repository). Although there are many great patterns to use repository for both but I would like to stick with this one.zhuber
@Disappointed has a good link for you. But be aware that UoW and Repository patterns are very much debated, some would say deprecated. Certainly in an EF/MVC environment, where DbContext and DbSet already fulfill most of this functionality.Henk Holterman
The (main) purpose of the the UoW and Repository patterns are to decouple the data access implementation from the rest of your application. A very good point pro using these patterns with EF is presented here: stackoverflow.com/a/21361903/1942895Rafael Companhoni
It is a good link to read. But I notice that that answer is the minority view over there.Henk Holterman

1 Answers

0
votes

I would like to recommend that you avoid the Repository pattern, for inserts/updates.

You should consider "command/query objects" as an alternative, you can find a bunch of interesting articles around this area, but here is a good one:

https://rob.conery.io/2014/03/03/repositories-and-unitofwork-are-not-a-good-idea/

You would stick to a single command object per command to enable simple transactions, avoiding the need for the complexity of the Unit Of Work pattern.

However, if you are thinking a Query object per query is overkill, this would often be right. Instead you might choose to start with a 'FooQueries' object, which is essentially a Repository but only for Queries. 'Foo' might be your 'domain aggregate' in the DDD sense.

Later, you might find splitting out individual query objects worthwhile if you want to add cross cutting concerns via attributes, you could even feed a query object into a pipeline.