EF core (code fi‎rst) 通过自定义 Migr‎ation History 实现多

来源:m-dot.com   作者:   发表时间:2020-02-17 05:49:03

写这篇文章的原因,其实由于我写EF core 实现多租户的时候,遇到的问题。

这里我遇到的最主要问题是:由于多租户的表使用的是同一个数据库。由于这个原因,无法通过Database.EnsureCreated() 自动创建多个结构相同但名字不同的表。

所以我在文中提到,需要自己跑脚本去创建多有的表。

虽然我依然认为在多租户的情况下使用sql管理表是更可靠的方案,但如果可以利用EF core原生提供的Migration机制,在运行时自动创建和更新数据表结构,那更加友好。

其实我们都知道,EF core (code first) 会在数据库中生成唯一一个 __EFMigrationHistory 表,数据库的版本记录在这里。

在我们文章的场景下,由于有多个租户同时使用,同一个表结构(Products)会出现多次,那么意思就是一个__EFMigrationHistory 无法同时记录多个租户的数据表版本。

好了,既然问题的关键已经知道了,我们可以在这里先把答案揭晓,在下问在详细说明实现方法:

图中可以看到,我们自定义MigrationHistory表,并且在一个数据下,同时出现了store1和store2的 MigrationHistory 表。

这是一个多租户系统,具体来说就是根据不同的租户,创建相同的所有数据表。

1. .net core app 3.1。在机器上安装好.net core SDK, 版本3.1

2. Mysql. 使用Pomelo.EntityFrameworkCore.MySql 包

3. EF core,Microsoft.EntityFrameworkCore, 版本3.1.1。这里必须要用3.1的,因为ef core3.0是面向.net standard 2.1.

4. EF core design,Microsoft.EntityFrameworkCore.Design, 版本 3.1.1

5. dotnet-ef tool, 版本 3.1.1

1.MigrationsAssembly, 利用此类去实现创建对应的Migration单元。

2. Migration files, 这里指的是一批Migration相关的文件,利用执行dotnet-ef 命令生成具体的文件,从而真正地去创建和更新数据库。

1. 运行dotnet-ef命令,生成Migration files

执行后,会在项目中的Migrations文件夹下生成多个*.cs文件,其实他们也是可执行C#对象

这3个文件中,主要起作用的是*_init.cs这个文件

打开之后我们需要对他进行修改

1.1 新增构造函数,并且在里面添加一个prefix 参数。

1.2 在Up方法中,对table Name进行修改,把prefix变量加在_Product前面(第21行)

1.3 在Down方法中,对table Name进行修改,把prefix变量加在_Product前面 (第39行)

2. 创建MigrationByTenantAssembly 文件。

由于上一步讲Migration file的构造函数修改了,理论上EF core已经五法通过默认的方式成功执行改Migration file了

这个类中没有什么特别的,关键在于29~37行。首先需要判断目标 Migration 对象的是否有一个构造函数的参数有且仅有一个string 类型

判断DbContext是否有实现ITenantDbContext接口。

利用Activator 创建 Migration 实例(把tenant Name传进构造函数)

3. 在MultipleTenancyExtension 类的AddDatabase方法中,添加自定义MigrationHistory表名

最关键的一点是第5行,调用 MigrationsHistoryTable 设置MigrationHistory表名

另外一点是第10行,用MigrationByTenantAssembly 类替换 EF core 中默认的实现(IMigrationsAssembly接口)

4. 在ProductController的构造函数中,修改成如下

Database.Migrate 的作用主要是在运行时可以执行数据库的创建和更新

跟系列文章一样,我们先调用创建product的接口分别在store1和store2中添加记录。

下面是store1 的查询结果

store1_Products 表数据

store2_Products 表数据

本文中我们介绍了ef core 的code first模式下是如何更新数据库的,并且通过添加 Migration 对象的构造函数 ,自行添加了必要参数。

通过替换EF core中默认的 IMigrationsAssembly 实现,MigrationByTenantAssembly 中自定对Migration对象实例化。

替换EF core中默认的MigrationHistory最终实现需求。

本文虽然只是一个示例,但是却可以在真实项目中使用相同的手段以实现需求。不过还是那句话,对于多租户情况下,我推荐使用db first模式。

编辑:

未经授权许可,不得转载或镜像
© Copyright © 1997-2019 by m-dot.com all rights reserved