Asp.Net Core 2.0 之旅---数据访问仓储模式的事务管理

之前在我的文章中,通过实例展示Asp.Net Core 2.0 之旅---AutoFac 仓储泛型的依赖注入,并在结尾处提到了事务的统一管理。

仓储的概念是DDD领域的一部分,仓储封装了获取数据的逻辑,领域对象无需和底层数据库打交道。但是从之前的仓储实现中,每个增删改查都显示的调用了SaveChanges方法,导致每次更改都提交事务。如果我们操作多个仓储对象时,就无法批量提交,无法实现Unit Of Work模式了(UOW模式是,通过事务,一次性提交所以的更改,保证了数据的完整性),要实现UOW,接下来就要对仓储实现的方法就行调整了。

1、定义IUnitOfWork接口,定义两个方法,SaveChanges 同步方法,SaveChangesAsync 异步方法

 public interface IUnitOfWork
    {
        /// <summary>
        /// 提交更改
        /// </summary>
        /// <returns></returns>
        int SaveChanges();
        /// <summary>
        /// 提交更改异步
        /// </summary>
        /// <returns></returns>
        Task<int> SaveChangesAsync();
        /// <summary>
        /// 开启事务
        /// </summary>
        void BeginTransaction();
        /// <summary>
        /// 提交事务
        /// </summary>
        void CommitTransaction();
        /// <summary>
        /// 回滚事务
        /// </summary>
        void RollBackTransaction();
    }

2、定义 IUnitOfWork的实现类UnitOfWork,定义泛型TDBContext其类型必须是DbContext,通过构造函数依赖注入_dbContext 

  public class UnitOfWork<TDBContext> : IUnitOfWork where TDBContext : DbContext
    {
        private readonly TDBContext _dbContext;

        public UnitOfWork(TDBContext dbContext)
        {
            _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
        }
        public int SaveChanges()
        {
            return _dbContext.SaveChanges();
        }

        public async Task<int> SaveChangesAsync()
        {
            return await _dbContext.SaveChangesAsync();
        }
        public void BeginTransaction()
        {
            _dbContext.Database.BeginTransaction();
        }

        public void CommitTransaction()
        {
            _dbContext.Database.CommitTransaction();
        }

        public void RollBackTransaction()
        {
            _dbContext.Database.RollbackTransaction();
        }
    }

3、修改仓储的实现类,其实现类的链接在文章顶部已经实现了,但是要把 this._context.SaveChanges();这行代码全部删除。这样就不会每次更改就会提交,而是交由IUnitOfWork 统一的提交事务。


4、注册IUnitOfWork的时候要注意,要确保 UnitOfWork和DBContext 在整个请求中共用同一个对象,这样才能通过IUnitOfWork 来一次性提交事务。AddDbContext这个方法它默认的生命周期为ServiceLifetime.Scoped,所以只需要注册IUnitOfWork的时候使用AddScoped方法,将其生命周期限定为Scoped,就能保证每次请求都是共用同一个对象。

            services.AddDbContext<YunSourseContext>(option => option.UseSqlServer(Configuration.GetConnectionString("Default"), b => b.UseRowNumberForPaging()));//配置sqlserver
            services.AddScoped<IUnitOfWork,UnitOfWork<YunSourseContext>>();//注入UOW依赖,确保每次请求都是同一个对象
5、代码改造完毕,接下来就要就行实例演示了

    1)通过构造函数依赖注入 _userIRepository 和 _unitOfWork ,将事务统一交由 _unitOfWork 来管理

        private readonly IRepository<User> _userIRepository;
        private readonly IUnitOfWork _unitOfWork;
        public UserManager(IRepository<User> userIRepository,IUnitOfWork unitOfWork)
        {
            _userIRepository = userIRepository;
            _unitOfWork = unitOfWork;
        

    2)连续插入两个实体:没有执行_unitOfWork.SaveChanges()之前,数据库中没有新增的数据,只有执行了_unitOfWork.SaveChanges(),数据库才新增了两条数据,说明只提交了一次更改,符合预期目的。

 var user = new User()  
          {  
              UserName = "1",  
              UserPwd = "12",  
              CreationTime = DateTime.Now,  
          };  
var user1 = new User()  
          {  
              UserName = "11",  
              UserPwd = "121",  
              CreationTime = DateTime.Now,  
          };  
          await _userIRepository.InsertAsync(user);  
          await _userIRepository.InsertAsync(user1);  
          _unitOfWork.SaveChanges();  
    3)进行事务操作:如下所示,InsertAndGetId这个方法,会将实体提交到数据库,并返回实体的主键Id,如果后面执行的过程中发生了异常,就需要回滚数据。用于数据的强一致性应用场景。

  var user = new User()
            {
                UserName = "1111",
                UserPwd = "12",
                CreationTime = DateTime.Now,
            };
            var user1 = new User()
            {
                UserName = "11",
                UserPwd = "121",
                CreationTime = DateTime.Now,
            };
            try
            {
                _unitOfWork.BeginTransaction();//开启事务
                var userId = _userIRepository.InsertAndGetId(user);//获取UserId,此时已经提交到数据库
                await _userIRepository.InsertAsync(user1);
                await _unitOfWork.SaveChangesAsync();//提交变更
                _unitOfWork.CommitTransaction();//提交事务
            }
            catch
            {
                _unitOfWork.RollBackTransaction();//回滚事务
                throw;
            }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值