NetCore基于EntityFramework和Aop的工作单元模式(UnitOfWork)简单实现
Unit of Work是什么
Unit of Work 是一种重要的设计模式。Unit of Work 模式提供了一种有效的方式来管理数据库事务和跟踪对数据库的所有更改。
使用 Unit of Work 模式的好处是多方面的。首先,它允许我们将多个数据库操作组合成一个事务。这意味着要么全部操作成功提交,要么都失败回滚。这确保了数据的完整性和一致性。
其次,Unit of Work 跟踪对数据库所做的所有更改。无论是插入、更新还是删除操作,都会被记录下来。在提交事务之前,可以检查并验证这些更改,以确保数据的正确性。
此外,通过优化数据库操作的执行顺序,Unit of Work 可以减少不必要的往返数据库的次数,从而提高性能。它还可以确保对同一实体的修改在同一个事务中进行,从而维护实体之间的一致性。
在实际开发中,Unit of Work 往往与仓储(Repository)模式一起使用。仓储负责处理数据的持久化和检索,而 Unit of Work 则负责管理仓储的工作单元和事务。这种组合可以提高代码的可维护性和可测试性
代码实现
创建工作单元的依赖接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public interface IUnitOfWork : IDisposable { Task<IDbContextTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default);
IDbContextTransaction BeginTransaction();
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
void CommitTransaction();
Task CommitTransactionAsync(CancellationToken cancellationToken = default);
void RollbackTransaction();
Task RollbackTransactionAsync(CancellationToken cancellationToken = default); }
|
接口实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
| public sealed class UnitOfWork<TDbContext> : IUnitOfWork, IDisposable, ITransientDependency where TDbContext : DbContext { public bool IsDisposed { get; private set; }
public bool IsCompleted { get; private set; }
private readonly TDbContext _dbContext;
private readonly IServiceProvider _serviceProvider;
public UnitOfWork(TDbContext dbContext) { _dbContext = dbContext ?? throw new ArgumentNullException($"db context {nameof(dbContext)} is null"); }
public async Task<IDbContextTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default) { IsCompleted = false; return await _dbContext.Database.BeginTransactionAsync(cancellationToken); }
public IDbContextTransaction BeginTransaction() { IsCompleted = false; return _dbContext.Database.CurrentTransaction ?? _dbContext.Database.BeginTransaction(); }
public async Task CommitTransactionAsync(CancellationToken cancellationToken = default) { if (IsCompleted) { return; }
IsCompleted = true; try { await _dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); await _dbContext.Database.CommitTransactionAsync(cancellationToken).ConfigureAwait(false); } catch (Exception ex) { await RollbackTransactionAsync(cancellationToken).ConfigureAwait(false); throw new Exception(ex.Message); } }
public void CommitTransaction() { if (IsCompleted) { return; }
IsCompleted = true; try { _dbContext.SaveChanges(); _dbContext.Database.CommitTransaction(); } catch (Exception x) { RollbackTransaction(); throw; } }
public async Task RollbackTransactionAsync(CancellationToken cancellationToken = default) { if (IsCompleted) { return; } await _dbContext.Database.RollbackTransactionAsync(cancellationToken).ConfigureAwait(false); }
public void RollbackTransaction() { if (IsCompleted) { return; } _dbContext.Database.RollbackTransaction(); }
public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { return await _dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); }
public void Dispose() { if (IsDisposed) { return; }
IsDisposed = true; } }
|
服务注入到容器中:
1
| services.AddTransient<IUnitOfWork, UnitOfWork>(); // 注册工作单元到容器
|
此时,工作单元已经添加到容器中,为了更方便的使用,我们可以使用AspNetCore框架自带的过滤器实现AOP的方式来使用工作单元。
我们默认接口是启用工作单元的,但为了更加全面,添加一个工作单元特性
1 2 3 4 5 6 7 8 9 10
| [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class DisabledUnitOfWorkAttribute : Attribute { public readonly bool Disabled;
public DisabledUnitOfWorkAttribute(bool disabled = true) { Disabled = disabled; } }
|
为了避免每次执行操作都要手动调用一下工作单元来进行保存,我们添加一个全局过滤器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
public class UnitOfWorkFilter : IAsyncActionFilter, IOrderedFilter {
private readonly ILogger<UnitOfWorkFilter> _logger; public UnitOfWorkFilter(ILogger<UnitOfWorkFilter> logger) { this._logger = logger; } internal const int FilterOrder = 999;
public int Order => FilterOrder;
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; var method = actionDescriptor.MethodInfo;
var httpContext = context.HttpContext;
if (method.IsDefined(typeof(DisabledUnitOfWorkAttribute), true)) { _ = await next();
return; }
_logger.LogInformation($@"{nameof(UnitOfWorkFilter)} Beginning");
var unitOfWorks = httpContext.RequestServices.GetServices<IUnitOfWork>(); foreach (var unitOfWork in unitOfWorks) { await unitOfWork.BeginTransactionAsync(); } try { await next(); foreach (var unitOfWork in unitOfWorks) { await unitOfWork.CommitTransactionAsync(); }
_logger.LogInformation($@"{nameof(UnitOfWorkFilter)} Ending"); } catch (Exception ex) { foreach (var d in unitOfWorks) { await d.RollbackTransactionAsync(); } throw; } } }
|
将过滤器添加到通信管道中
1 2 3 4 5
| services.AddControllers(options => { options.Filters.Add<UnitOfWorkFilter>(); });
|
完结:散花(只是简单实现,存在很多不足。)