.NET Core开发实战(第28课:工作单元模式(UnitOfWork):管理好你的事务)--学习笔记...
生活随笔
收集整理的這篇文章主要介紹了
.NET Core开发实战(第28课:工作单元模式(UnitOfWork):管理好你的事务)--学习笔记...
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
28 | 工作單元模式(UnitOfWork):管理好你的事務
工作單元模式有如下幾個特性:
1、使用同一上下文
2、跟蹤實體的狀態
3、保障事務一致性
我們對實體的操作,最終的狀態都是應該如實保存到我們的存儲中,進行持久化
接下來看一下代碼
為了實現工作單元模式,這里定義了一個工作單元的接口
public interface IUnitOfWork : IDisposable {Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default); }這兩個方法的區別是:一個是返回的 int 是指我們影響的數據條數,另外一個返回 bool 表示我們保存是否成功,本質上這兩個方法達到的效果是相同的
另外還定義了一個事務管理的接口
public interface ITransaction {// 獲取當前事務IDbContextTransaction GetCurrentTransaction();// 判斷當前事務是否開啟bool HasActiveTransaction { get; }// 開啟事務Task<IDbContextTransaction> BeginTransactionAsync();// 提交事務Task CommitTransactionAsync(IDbContextTransaction transaction);// 事務回滾void RollbackTransaction(); }在實現上我們是借助 EF 來實現工作單元模式的
看一下 EFContext 的定義
/// <summary> /// DbContext 是 EF 的基類,然后實現了 UnitOfWork 的接口和事務的接口 /// </summary> public class EFContext : DbContext, IUnitOfWork, ITransaction {protected IMediator _mediator;ICapPublisher _capBus;// 后面的章節會詳細講到這兩個參數public EFContext(DbContextOptions options, IMediator mediator, ICapPublisher capBus) : base(options){_mediator = mediator;_capBus = capBus;}#region IUnitOfWorkpublic async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default){var result = await base.SaveChangesAsync(cancellationToken);//await _mediator.DispatchDomainEventsAsync(this);return true;}可以看到這個方法實際上與上面的方法是相同的,所以這個方法可以不實現//public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)//{// return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);//}#endregion#region ITransactionprivate IDbContextTransaction _currentTransaction;// 把當前的事務用一個字段存儲public IDbContextTransaction GetCurrentTransaction() => _currentTransaction;// 獲取當前的事務就是返回存儲的私有對象public bool HasActiveTransaction => _currentTransaction != null;// 事務是否開啟是判斷當前這個事務是否為空/// <summary>/// 開啟事務/// </summary>/// <returns></returns>public Task<IDbContextTransaction> BeginTransactionAsync(){if (_currentTransaction != null) return null;_currentTransaction = Database.BeginTransaction(_capBus, autoCommit: false);return Task.FromResult(_currentTransaction);}/// <summary>/// 提交事務/// </summary>/// <param name="transaction">當前事務</param>/// <returns></returns>public async Task CommitTransactionAsync(IDbContextTransaction transaction){if (transaction == null) throw new ArgumentNullException(nameof(transaction));if (transaction != _currentTransaction) throw new InvalidOperationException($"Transaction {transaction.TransactionId} is not current");try{await SaveChangesAsync();// 將當前所有的變更都保存到數據庫transaction.Commit();}catch{RollbackTransaction();throw;}finally{if (_currentTransaction != null){// 最終需要把當前事務進行釋放,并且置為空// 這樣就可以多次的開啟事務和提交事務_currentTransaction.Dispose();_currentTransaction = null;}}}/// <summary>/// 回滾/// </summary>public void RollbackTransaction(){try{_currentTransaction?.Rollback();}finally{if (_currentTransaction != null){_currentTransaction.Dispose();_currentTransaction = null;}}}#endregion }另外一個我們還是需要關注的一點就是如何管理我們的事務
這里有一個類 TransactionBehavior,這個類是用來注入我們的事務的管理過程的,具體它是怎么工作的在后續的章節會講到,這里先關注它的實現過程
public class TransactionBehavior<TDbContext, TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TDbContext : EFContext {ILogger _logger;TDbContext _dbContext;ICapPublisher _capBus;public TransactionBehavior(TDbContext dbContext, ICapPublisher capBus, ILogger logger){_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));_capBus = capBus ?? throw new ArgumentNullException(nameof(capBus));_logger = logger ?? throw new ArgumentNullException(nameof(logger));}public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next){var response = default(TResponse);var typeName = request.GetGenericTypeName();try{// 首先判斷當前是否有開啟事務if (_dbContext.HasActiveTransaction){return await next();}// 定義了一個數據庫操作執行的策略,比如說可以在里面嵌入一些重試的邏輯,這里創建了一個默認的策略var strategy = _dbContext.Database.CreateExecutionStrategy();await strategy.ExecuteAsync(async () =>{Guid transactionId;using (var transaction = await _dbContext.BeginTransactionAsync())using (_logger.BeginScope("TransactionContext:{TransactionId}", transaction.TransactionId)){_logger.LogInformation("----- 開始事務 {TransactionId} ({@Command})", transaction.TransactionId, typeName, request);response = await next();// next 實際上是指我們的后續操作,這里的模式有點像之前講的中間件模式_logger.LogInformation("----- 提交事務 {TransactionId} {CommandName}", transaction.TransactionId, typeName);await _dbContext.CommitTransactionAsync(transaction);transactionId = transaction.TransactionId;}});return response;}catch (Exception ex){_logger.LogError(ex, "處理事務出錯 {CommandName} ({@Command})", typeName, request);throw;}} }回過頭來看一下我們的 EFContext,EFContext 實現 IUnitOfWork,工作單元模式的核心,它實現了事務的管理和工作單元模式,我們就可以借助 EFContext 來實現我們的倉儲層
總結
以上是生活随笔為你收集整理的.NET Core开发实战(第28课:工作单元模式(UnitOfWork):管理好你的事务)--学习笔记...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何用 Blazor 实现 Ant De
- 下一篇: .NET Core 如何生成信用卡卡号