变形精怪

树有年轮,人有皱纹

导航

abp一代数据迁解析

Posted on 2020-07-07 20:57  变形精怪  阅读(1647)  评论(0编辑  收藏  举报

abp版本5.9

概述

数据迁移无非就是两件事情,1、创建数据库,并根据实体创建对应的表;2、添加一些初始数据

abp的数据迁移也是完成这两件事,比较特殊的是它是多租户saas系统,而且支持不同的租户有独立的数据库。所以abp中的迁移要先迁移户主Host,再迁移租户Tenant的数据库

它的迁移定义了一个架子,这个架子定义了abp数据库迁移的几个步骤,在这些步骤挖了几个坑,留给我们来自定义。

为了我们使用更方便,它还实现了一些简单的默认数据的初始化

所以我们需要先搞懂abp数据库迁移的基本原理,真正使用时我们只需要去填那几个坑就可以了。

核心步骤

  1. 创建并初始化AbpBootstrapper,有点类似Main函数的功效,只不过它是abp系统的起点。它创建依赖注入容器,并注册各abp模块,并处理它们的依赖关系和执行顺序
  2. 通过依赖注入获取MultiTenantMigrateExecuter并执行Run方法,内部逻辑如下:
    1. 通过依赖注入获取AbpZeroDbMigrator,
    2. 拿到户主(Host)的连接字符串
    3. 执行AbpZeroDbMigrator.CreateOrMigrateForHost 并传递一个委托。主要是创建户主和相应的用户角色权限等信息。我们可以在这里定义创建更多租户的逻辑
      1. 创建户主(Host)数据库和表结构
      2. 执行委托创建初始数据,其中包括户主(host)的用户角色权限等
    4. 获取上一步骤创建好的更多租户,遍历它们逐一做数据库迁移。使用AbpZeroDbMigrator.CreateOrMigrateForTenant(tenant),AbpZeroDbMigrator具体实现由我们提供,但它有抽象类,所以如果需要我们可以重写几个方法

一般情况红色字体标注部分是我们比较关心的,主要是在迁移时添加更多租户;为每个租户添加默认数据;

模板项目下载后,有个XXX.Migrator项目,它就是abp数据库迁移程序,是个控制台。只是使用的话看官方文档就可以了。下面分别说说里面的几个核心类

AbpBootstrapper

这个我没去细看,但是根据经验应该能猜到它是ABP系统的起点,初始化时会去创建全局的依赖注入容器,从入口模块开始,根据模块间的依赖最终加载所需要的所有模块,并根据依赖顺序执行模块中相应的方法。这里主要说迁移,所以不深入了,参考官方文档就可以了 abp启动配置 模块系统  。

默认情况下,创建AbpBootstrapper时是从XXXMigratorModule模块开始加载的,而它依赖[DependsOn(typeof(XXXEntityFrameworkModule))],而后者又依赖XXXCoreModule,当然这条依赖线可能会更长,具体看你的项目了。

MultiTenantMigrateExecuter

AbpBootstrapper创建并初始化后,依赖注入框架就可以使用了,且各模块也初始化好了。迁移时会从容器中取出一个MultiTenantMigrateExecuter,把它理解为多租户迁移执行器,它是在MultiTenantMigrateExecuter模块初始化时注册的。它负责上面步骤的2.1 ——2.4

它主要是用来定义迁移的大步骤,虽然我们可以来修改这里的代码,但是通常没啥必要。核心步骤就是

  1. 从容器中取得AbpZeroDbMigrator
  2. 执行AbpZeroDbMigrator.CreateOrMigrateForHost 初始化户主的数据库并添加默认数据
  3. 执行AbpZeroDbMigrator.CreateOrMigrateForTenant(tenant);为每一个租户创建数据库和初始数据

先不管AbpZeroDbMigrator是哪注册的,

在步骤2中执行CreateOrMigrateForHost 时丢入了一个委托SeedHelper.SeedHostDb,它默认情况下初始化Host数据库,并添加户主和默认的用户、角色、权限等数据。所以如果我们只是先在迁移时添加更多租户,可以来修改SeedHelper.SeedHostDb静态方法。

步骤3默认情况下啥都没干,但是在这个大步骤中执行了它,所以如果我们想为每个租户添加一些初始数据,我们应该提供AbpZeroDbMigrator.CreateOrMigrateForTenant(tenant);方法,具体如何做呢?往下看

AbpZeroDbMigrator

MultiTenantMigrateExecuter定义了迁移的几个大步骤,初始化Host数据库并添加默认数据;初始化租户数据库并添加默认数据;这两个任务的具体逻辑是交给AbpZeroDbMigrator来完成的

AbpZeroDbMigrator是我们提供的,定义在XXX.EntityFrameworkCore项目中,它实现IAbpZeroDbMigrator接口。它在模块的初始化方法中注册打动依赖注入容器的。

为了我们使用更简单,abp为我们提供一个抽象类AbpZeroDbMigrator<TDbContext> ,它按简单方式实现了:1、租户数据库的创建和初始数据的添加;2、租户数据库的创建和初始数据的添加;数据库的创建的直接调用DbContext.DataBase.Migrate(),这是EF提供的功能,初始数据的添加则是让调用方来提供,就是个委托,在创建数据库后会回调这个委托。

因此下载的abp项目模板中XXX.EntityFrameworkCore中定义的XXXDbMigrator继承了AbpZeroDbMigrator<TDbContext>,但却没有实现,因为父类都做好了。

到此,数据库的创建最终是efcore的Migrate方法完成的,Host户主的初始数据的添加的委托是直接由SeedHelper.SeedHostDb来提供的。租户的初始数据的添加我们可以在自己的XXXDbMigrator中重写CreateOrMigrateForTenant方法来实现,水在这个方法内我们可以通过参数拿到当前的租户,委托中的参数为我们提供了当前租户的dbContext,因此我们不用关心这个dbcontext是每个租户一个,还是各租户使用的是同一个数据库。

总结

要在数据库初始化时添加更多租户,在XXX.EntityFrameworkCore/Seed/SeedHelper中改

要为每个租户添加一些初始数据是,在XXX.EntityFrameworkCore/AbpZeroDbMigrator中重写CreateOrMigrateForTenant(AbpTenantBase tenant),然后调用父类的CreateOrMigrateForTenant(AbpTenantBase tenant, Action<TDbContext> seedAction),提供自己的委托来添加初始数据