简体   繁体   中英

How to implement Transactions with Generic Repository Pattern?

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:

IGenericRepository

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)
   {
        this.arepo=arepo;
        this.brepo=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?

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:

 context.Database.BeginTransaction()

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM