数据迁移无非就是两件事情,1、创建数据库,并根据实体创建对应的表;2、添加一些初始数据
abp的数据迁移也是完成这两件事,比较特殊的是它是多租户saas系统,而且支持不同的租户有独立的数据库。所以abp中的迁移要先迁移户主Host,再迁移租户Tenant的数据库
它的迁移定义了一个架子,这个架子定义了abp数据库迁移的几个步骤,在这些步骤挖了几个坑,留给我们来自定义。
为了我们使用更方便,它还实现了一些简单的默认数据的初始化
所以我们需要先搞懂abp数据库迁移的基本原理,真正使用时我们只需要去填那几个坑就可以了。
核心步骤创建并初始化AbpBootstrapper,有点类似Main函数的功效,只不过它是abp系统的起点。它创建依赖注入容器,并注册各abp模块,并处理它们的依赖关系和执行顺序
通过依赖注入获取MultiTenantMigrateExecuter并执行Run方法,内部逻辑如下:
通过依赖注入获取AbpZeroDbMigrator,
拿到户主(Host)的连接字符串
执行AbpZeroDbMigrator.CreateOrMigrateForHost 并传递一个委托。主要是创建户主和相应的用户角色权限等信息。我们可以在这里定义创建更多租户的逻辑
创建户主(Host)数据库和表结构
执行委托创建初始数据,其中包括户主(host)的用户角色权限等
获取上一步骤创建好的更多租户,遍历它们逐一做数据库迁移。使用AbpZeroDbMigrator.CreateOrMigrateForTenant(tenant),AbpZeroDbMigrator具体实现由我们提供,但它有抽象类,所以如果需要我们可以重写几个方法
一般情况红色字体标注部分是我们比较关心的,主要是在迁移时添加更多租户;为每个租户添加默认数据;
模板项目下载后,有个XXX.Migrator项目,它就是abp数据库迁移程序,是个控制台。只是使用的话看官方文档就可以了。下面分别说说里面的几个核心类
AbpBootstrapper这个我没去细看,但是根据经验应该能猜到它是ABP系统的起点,初始化时会去创建全局的依赖注入容器,从入口模块开始,根据模块间的依赖最终加载所需要的所有模块,并根据依赖顺序执行模块中相应的方法。这里主要说迁移,所以不深入了,参考官方文档就可以了 abp启动配置 模块系统 。
默认情况下,创建AbpBootstrapper时是从XXXMigratorModule模块开始加载的,而它依赖[DependsOn(typeof(XXXEntityFrameworkModule))],而后者又依赖XXXCoreModule,当然这条依赖线可能会更长,具体看你的项目了。
MultiTenantMigrateExecuterAbpBootstrapper创建并初始化后,依赖注入框架就可以使用了,且各模块也初始化好了。迁移时会从容器中取出一个MultiTenantMigrateExecuter,把它理解为多租户迁移执行器,它是在MultiTenantMigrateExecuter模块初始化时注册的。它负责上面步骤的2.1 ——2.4
它主要是用来定义迁移的大步骤,虽然我们可以来修改这里的代码,但是通常没啥必要。核心步骤就是
从容器中取得AbpZeroDbMigrator
执行AbpZeroDbMigrator.CreateOrMigrateForHost 初始化户主的数据库并添加默认数据
执行AbpZeroDbMigrator.CreateOrMigrateForTenant(tenant);为每一个租户创建数据库和初始数据
先不管AbpZeroDbMigrator是哪注册的,
在步骤2中执行CreateOrMigrateForHost 时丢入了一个委托SeedHelper.SeedHostDb,它默认情况下初始化Host数据库,并添加户主和默认的用户、角色、权限等数据。所以如果我们只是先在迁移时添加更多租户,可以来修改SeedHelper.SeedHostDb静态方法。
步骤3默认情况下啥都没干,但是在这个大步骤中执行了它,所以如果我们想为每个租户添加一些初始数据,我们应该提供AbpZeroDbMigrator.CreateOrMigrateForTenant(tenant);方法,具体如何做呢?往下看
AbpZeroDbMigratorMultiTenantMigrateExecuter定义了迁移的几个大步骤,初始化Host数据库并添加默认数据;初始化租户数据库并添加默认数据;这两个任务的具体逻辑是交给AbpZeroDbMigrator来完成的
AbpZeroDbMigrator是我们提供的,定义在XXX.EntityFrameworkCore项目中,它实现IAbpZeroDbMigrator接口。它在模块的初始化方法中注册打动依赖注入容器的。
为了我们使用更简单,abp为我们提供一个抽象类AbpZeroDbMigrator<TDbContext> ,它按简单方式实现了:1、租户数据库的创建和初始数据的添加;2、租户数据库的创建和初始数据的添加;数据库的创建的直接调用DbContext.DataBase.Migrate(),这是EF提供的功能,初始数据的添加则是让调用方来提供,就是个委托,在创建数据库后会回调这个委托。
因此下载的abp项目模板中XXX.EntityFrameworkCore中定义的XXXDbMigrator继承了AbpZeroDbMigrator<TDbContext>,但却没有实现,因为父类都做好了。