[Abp vNext 源码分析] - 14. EntityFramework Core 的集成 (5)

以下代码才是在真正地创建 DbContext 实例。

public TDbContext CreateDbContextWithTransaction(IUnitOfWork unitOfWork) { var transactionApiKey = $"EntityFrameworkCore_{DbContextCreationContext.Current.ConnectionString}"; var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as EfCoreTransactionApi; // 没有取得缓存。 if (activeTransaction == null) { var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>(); // 判断是否指定了事务隔离级别,并开始事务。 var dbtransaction = unitOfWork.Options.IsolationLevel.HasValue ? dbContext.Database.BeginTransaction(unitOfWork.Options.IsolationLevel.Value) : dbContext.Database.BeginTransaction(); // 跟工作单元绑定添加一个已经激活的事务。 unitOfWork.AddTransactionApi( transactionApiKey, new EfCoreTransactionApi( dbtransaction, dbContext ) ); // 返回构造好的数据库上下文。 return dbContext; } else { DbContextCreationContext.Current.ExistingConnection = activeTransaction.DbContextTransaction.GetDbTransaction().Connection; var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>(); if (dbContext.As<DbContext>().HasRelationalTransactionManager()) { dbContext.Database.UseTransaction(activeTransaction.DbContextTransaction.GetDbTransaction()); } else { dbContext.Database.BeginTransaction(); //TODO: Why not using the new created transaction? } activeTransaction.AttendedDbContexts.Add(dbContext); return dbContext; } } 2.4 数据过滤器

ABP vNext 还提供了数据过滤器机制,可以让你根据指定的标识过滤数据,例如租户 Id 和软删除标记。它的基本接口定义在 Volo.Abp.Data 项目的 IDataFilter.cs 文件中,提供了启用、禁用、检测方法。

public interface IDataFilter<TFilter> where TFilter : class { IDisposable Enable(); IDisposable Disable(); bool IsEnabled { get; } } public interface IDataFilter { IDisposable Enable<TFilter>() where TFilter : class; IDisposable Disable<TFilter>() where TFilter : class; bool IsEnabled<TFilter>() where TFilter : class; }

默认实现也在该项目下面的 DataFilter.cs 文件,首先看以下 IDataFilter 的默认实现 DataFilter,内部有一个解析器和并发字典。这个并发字典存储了所有的过滤器,其键是真实过滤器的类型(ISoftDelete 或 IMultiTenant),值是 DataFilter<TFilter>,具体对象根据 TFilter 的不同而不同。

public class DataFilter : IDataFilter, ISingletonDependency { private readonly ConcurrentDictionary<Type, object> _filters; private readonly IServiceProvider _serviceProvider; public DataFilter(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; _filters = new ConcurrentDictionary<Type, object>(); } // ... }

看一下其他的方法,都是对 IDataFilter<Filter> 的包装。

public class DataFilter : IDataFilter, ISingletonDependency { // ... public IDisposable Enable<TFilter>() where TFilter : class { return GetFilter<TFilter>().Enable(); } public IDisposable Disable<TFilter>() where TFilter : class { return GetFilter<TFilter>().Disable(); } public bool IsEnabled<TFilter>() where TFilter : class { return GetFilter<TFilter>().IsEnabled; } private IDataFilter<TFilter> GetFilter<TFilter>() where TFilter : class { // 并发字典当中获取指定类型的过滤器,如果不存在则从 IoC 中解析。 return _filters.GetOrAdd( typeof(TFilter), () => _serviceProvider.GetRequiredService<IDataFilter<TFilter>>() ) as IDataFilter<TFilter>; } }

这么看来,IDataFilter 叫做 IDataFilterManager 更加合适一点,最开始我还没搞明白两个接口和实现的区别,真正搞事情的是 DataFilter<Filter>。

public class DataFilter<TFilter> : IDataFilter<TFilter> where TFilter : class { public bool IsEnabled { get { EnsureInitialized(); return _filter.Value.IsEnabled; } } // 注入数据过滤器配置类。 private readonly AbpDataFilterOptions _options; // 用于存储过滤器的启用状态。 private readonly AsyncLocal<DataFilterState> _filter; public DataFilter(IOptions<AbpDataFilterOptions> options) { _options = options.Value; _filter = new AsyncLocal<DataFilterState>(); } // ... // 确保初始化成功。 private void EnsureInitialized() { if (_filter.Value != null) { return; } // 如果过滤器的默认状态为 NULL,优先从配置类中取得指定过滤器的默认启用状态,如果不存在则默认为启用。 _filter.Value = _options.DefaultStates.GetOrDefault(typeof(TFilter))?.Clone() ?? new DataFilterState(true); } }

数据过滤器在设计的时候,也是按照工作单元的形式进行设计的。不论是启用还是停用都是范围性的,会返回一个用 DisposeAction 包装的可释放对象,这样在离开 using 语句块的时候,就会还原为来的状态。比如调用 Enable() 方法,在离开 using 语句块之后,会调用 Disable() 禁用掉数据过滤器。

public IDisposable Enable() { if (IsEnabled) { return NullDisposable.Instance; } _filter.Value.IsEnabled = true; return new DisposeAction(() => Disable()); } public IDisposable Disable() { if (!IsEnabled) { return NullDisposable.Instance; } _filter.Value.IsEnabled = false; return new DisposeAction(() => Enable()); } 2.4.1 MongoDb 与 Memory 的集成

[Abp vNext 源码分析] - 14. EntityFramework Core 的集成

可以看到有两处使用,分别是 Volo.Abp.Domain 项目与 Volo.Abp.EntityFrameworkCore 项目。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjzfw.html