[Abp 源码分析]七、仓储与 Entity Framework Core (3)

第一个字典是存放处在激活状态的 DbContext 集合,第二个是 IIocResolver 用于解析组件所需要的解析器,第三个是数据库上下文的解析器用于创建 DbContext 的,第四个是用于查找 DbContext 的 Matcher,最后一个就是用于 EF Core 事物处理的东东。

根据 UnitOfWork 的调用顺序,首先看查看 BeginUow() 方法:

if (Options.IsTransactional == true) { _transactionStrategy.InitOptions(Options); }

没什么特殊操作,就拿着 UOW 对象的 Options 去初始化事物策略。

之后按照 UOW 的调用顺序(PS:如果看的一头雾水可以去看一下之前文章针对 UOW 的讲解),会调用基类的 CompleteAsync() 方法,在其内部则是会调用 EF Core UOW 实现的 CompleteUowAsync() 方法,其定义如下:

protected override async Task CompleteUowAsync() { await SaveChangesAsync(); CommitTransaction(); } public override async Task SaveChangesAsync() { foreach (var dbContext in GetAllActiveDbContexts()) { await SaveChangesInDbContextAsync(dbContext); } } private void CommitTransaction() { if (Options.IsTransactional == true) { _transactionStrategy.Commit(); } }

内部很简单,两句话,第一句话遍历所有激活的 DbContext ,然后调用其 SaveChanges() 提交更改到数据库当中。

之后呢,第二句话就是使用 DbContext 的 dbContext.Database.CommitTransaction(); 方法来提交一个事务咯。

public void Commit() { foreach (var activeTransaction in ActiveTransactions.Values) { activeTransaction.DbContextTransaction.Commit(); foreach (var dbContext in activeTransaction.AttendedDbContexts) { if (dbContext.HasRelationalTransactionManager()) { continue; //Relational databases use the shared transaction } dbContext.Database.CommitTransaction(); } } } 2.2 数据库上下文提供器

这个玩意儿的定义如下:

public interface IDbContextProvider<out TDbContext> where TDbContext : DbContext { TDbContext GetDbContext(); TDbContext GetDbContext(MultiTenancySides? multiTenancySide ); }

很简单的作用,获取指定类型的数据库上下文,他的标准实现是 UnitOfWorkDbContextProvider<TDbContext>,它依赖于 UOW ,使用 UOW 的 GetDbContext<TDbContext>() 方法来取得数据库上下文。

整个关系如下:

[Abp 源码分析]七、仓储与 Entity Framework Core

2.3 多数据库支持

在 Abp 内部针对多数据库支持是通过覆写 IConnectionStringResolver 来实现的,这个操作在之前的文章里面已经讲过,这里仅讲解它如何在 Abp 内部实现解析的。

IConnectionStringResolver 是在 EF 的 Uow 才会用到,也就是创建 DbContext 的时候:

public virtual TDbContext GetOrCreateDbContext<TDbContext>(MultiTenancySides? multiTenancySide = null) where TDbContext : DbContext { var concreteDbContextType = _dbContextTypeMatcher.GetConcreteType(typeof(TDbContext)); var connectionStringResolveArgs = new ConnectionStringResolveArgs(multiTenancySide); connectionStringResolveArgs["DbContextType"] = typeof(TDbContext); connectionStringResolveArgs["DbContextConcreteType"] = concreteDbContextType; // 这里调用了 Resolver var connectionString = ResolveConnectionString(connectionStringResolveArgs); // 创建 DbContext dbContext = _transactionStrategy.CreateDbContext<TDbContext>(connectionString, _dbContextResolver); return (TDbContext)dbContext; } // 传入了 ConnectionStringResolveArgs 里面包含了实体类型信息哦 protected virtual string ResolveConnectionString(ConnectionStringResolveArgs args) { return ConnectionStringResolver.GetNameOrConnectionString(args); }

他这里的默认实现叫做 DefaultConnectionStringResolver ,就是从 IAbpStartupConfiguration 里面拿去用户在启动模块配置的 DefaultNameOrConnectionString 字段作为自己的默认数据库连接字符串。

在之前的 文章 的思路也是通过传入的 ConnectionStringResolveArgs 参数来判断传入的 Type,从而来根据不同的 DbContext 返回不同的连接串。

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

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