using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Linq; using System.Linq.Expressions; using System.Threading; namespace FreeSql { /// /// 仓储的工作单元管理器 /// public class RepositoryUnitOfWorkManager : IDisposable { IFreeSql _fsql; List _uows = new List(); bool _isNotSupported = false; public RepositoryUnitOfWorkManager(IFreeSql fsql) { _fsql = fsql ?? throw new ArgumentNullException($"{nameof(RepositoryUnitOfWorkManager)} 构造参数 {nameof(fsql)} 不能为 null"); } ~RepositoryUnitOfWorkManager() => this.Dispose(); int _disposeCounter; public void Dispose() { if (Interlocked.Increment(ref _disposeCounter) != 1) return; try { Exception exception = null; for (var a = _uows.Count - 1; a >= 0; a--) { try { if (exception == null) _uows[a].Commit(); else _uows[a].Rollback(); } catch (Exception ex) { if (exception == null) exception = ex; } } if (exception != null) throw exception; } finally { _uows.Clear(); GC.SuppressFinalize(this); } } public enum Propagation { /// /// 如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,默认的选择。 /// Requierd, /// /// 支持当前事务,如果没有当前事务,就以非事务方法执行。 /// Supports, /// /// 使用当前事务,如果没有当前事务,就抛出异常。 /// Mandatory, /// /// 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 /// NotSupported, /// /// 以非事务方式执行操作,如果当前事务存在则抛出异常。 /// Never, /// /// 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,就新建一个事务。 /// Nested } public IRepositoryUnitOfWork Begin(Propagation propagation, IsolationLevel? isolationLevel = null) { if (propagation == Propagation.Requierd) { if (_isNotSupported == false) { for (var a = _uows.Count - 1; a >= 0; a--) if (_uows[a].GetOrBeginTransaction(false) != null) return new UnitOfWorkProxy(_uows[a]); } var uow = new RepositoryUnitOfWork(_fsql); if (isolationLevel != null) uow.IsolationLevel = isolationLevel.Value; try { uow.GetOrBeginTransaction(); } catch { uow.Dispose(); throw; } _uows.Add(uow); return uow; } if (propagation == Propagation.Supports) { if (_isNotSupported == false) { for (var a = _uows.Count - 1; a >= 0; a--) if (_uows[a].GetOrBeginTransaction(false) != null) return new UnitOfWorkProxy(_uows[a]); } return new UnitOfWorkNothing(_fsql); } if (propagation == Propagation.Mandatory) { if (_isNotSupported == false) { for (var a = _uows.Count - 1; a >= 0; a--) if (_uows[a].GetOrBeginTransaction(false) != null) return new UnitOfWorkProxy(_uows[a]); throw new Exception("Propagation_Mandatory: 使用当前事务,如果没有当前事务,就抛出异常"); } throw new Exception("Propagation_Mandatory: 使用当前事务,如果没有当前事务,就抛出异常(NotSupported 事务挂起中)"); } if (propagation == Propagation.NotSupported) { if (_isNotSupported == false) { _isNotSupported = true; return new UnitOfWorkNothing(_fsql) { OnDispose = () => _isNotSupported = false }; } return new UnitOfWorkNothing(_fsql); } if (propagation == Propagation.Never) { if (_isNotSupported == false) { for (var a = _uows.Count - 1; a >= 0; a--) if (_uows[a].GetOrBeginTransaction(false) != null) throw new Exception("Propagation_Never: 以非事务方式执行操作,如果当前事务存在则抛出异常"); } return new UnitOfWorkNothing(_fsql); } if (propagation == Propagation.Nested) { var uow = new RepositoryUnitOfWork(_fsql); if (isolationLevel != null) uow.IsolationLevel = isolationLevel.Value; try { uow.GetOrBeginTransaction(); } catch { uow.Dispose(); throw; } _uows.Add(uow); return uow; } throw new NotImplementedException(); } class UnitOfWorkProxy : IRepositoryUnitOfWork { IRepositoryUnitOfWork _baseUow; public UnitOfWorkProxy(IRepositoryUnitOfWork baseUow) => _baseUow = baseUow; public IsolationLevel? IsolationLevel { get => _baseUow.IsolationLevel; set { } } public DbContext.EntityChangeReport EntityChangeReport => _baseUow.EntityChangeReport; public bool Enable => _baseUow.Enable; public void Close() => _baseUow.Close(); public void Open() => _baseUow.Open(); public DbTransaction GetOrBeginTransaction(bool isCreate = true) => _baseUow.GetOrBeginTransaction(isCreate); public void Commit() => this.Dispose(); public void Rollback() => _baseUow.Rollback(); public void Dispose() { } public IBaseRepository GetRepository(Expression> filter = null) where TEntity : class => _baseUow.GetRepository(filter); public IBaseRepository GetRepository(Expression> filter = null) where TEntity : class => _baseUow.GetRepository(filter); public IBaseRepository GetGuidRepository(Expression> filter = null, Func asTable = null) where TEntity : class => _baseUow.GetGuidRepository(filter); } class UnitOfWorkNothing : IRepositoryUnitOfWork { internal IFreeSql _fsql; internal Action OnDispose; public UnitOfWorkNothing(IFreeSql fsql) => _fsql = fsql; public IsolationLevel? IsolationLevel { get; set; } public DbContext.EntityChangeReport EntityChangeReport { get; } = new DbContext.EntityChangeReport(); public bool Enable { get; } public void Close() { } public void Open() { } public DbTransaction GetOrBeginTransaction(bool isCreate = true) => null; public void Commit() { if (EntityChangeReport != null && EntityChangeReport.OnChange != null && EntityChangeReport.Report.Any() == true) EntityChangeReport.OnChange.Invoke(EntityChangeReport.Report); this.Dispose(); } public void Rollback() => this.Dispose(); public void Dispose() { EntityChangeReport?.Report.Clear(); OnDispose?.Invoke(); } public IBaseRepository GetRepository(Expression> filter = null) where TEntity : class => new DefaultRepository(_fsql, filter); public IBaseRepository GetRepository(Expression> filter = null) where TEntity : class => new DefaultRepository(_fsql, filter); public IBaseRepository GetGuidRepository(Expression> filter = null, Func asTable = null) where TEntity : class => new GuidRepository(_fsql, filter, asTable); } } }