How to implement Transactions with Generic Repository Pattern? entity-framework-core generic-repository repository-pattern unit-of-work


I am developing a .NET Core application where I leverage the Generic Repository pattern and I would like to know how can I implement a transaction:


public interface IGenericRepository<T>
        Task InsertAsync(T insert);
        Task<bool> RemoveAsync(object id);
        Task UpdateAsync(T entity);
        Task<T> GetByIdAsync(object id,string includeProperties="");
        Task<IQueryable<T>> GetAsync(Expression<Func<T, bool>> filter=null,
                                     int? skip=null,
                                     int? take=null,
                                     Func<IQueryable<T>,IOrderedQueryable<T>> orderBy = null,
                                     string includeProperties = "");
        Task SaveAsync();

I was looking at this implementation which uses UnitOfWork as well, but in .NET Core, I do not have a DbContextTransaction.

I am not using UnitOfWork yet. Currently my service looks like this:

public class SomeService
   IGenericRepository<A> arepo;
   IGenericRepository<B> brepo;
   public SomeService(IGenericRepository<A> arepo,IGenericRepository<B> brepo)
   public async Task DoTransaction(id)
        var a=await arepo.GeyById(id)
        await brepo.RemoveAsync(a.Id);
        await brepo.SaveChangesAsync();
        await arepo.InsertAsync([something]);
        await arepo.SaveChanges();

I would want to make this transactional and also, avoid using SaveChangesAsync for all repositories that get involved.

What would be a solution?

1/7/2020 11:25:51 AM

Accepted Answer

Well I am not expert in entity framework, but I am answering in terms of repository and unit of work.

To begin with, avoid unnecessary wrapper of additional generic repository as you are already using full-ORM. Please refer to this answer.

but in .NET Core i do not have a DbContextTransaction.

The DbContextTransaction is important but not a key for implementing unit of work in this case. What is important is DBContext. It is DBContext that tracks and flushes the changes. You call SaveChanges on DBContext to notify that you are done.

I would want to make this transactional

I am sure there must be something available to replace DbContextTransaction or to represent transaction.

One way suggested by Microsoft is to use it as below:


where context is DbContext.

Other way is explained here.

also ,avoid using SaveChangesAsync for all repos that get involved

That is possible. Do not put SaveChanges in repositories. Put it in separate class. Inject that class in each concrete/generic repository. Finally, simply call SaveChanges once when you are done. For sample code, you can have a look at this question. But, code in that question have a bug which is fixed in the answer I provided to it.

1/7/2020 11:19:25 AM

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow