ABP框架入门踩坑-配置数据库表前缀

配置数据库表前缀

ABP踩坑记录-目录html

本篇其实和ABP关系并不大,主要是EF Core的一些应用-.-。数据库

原由

支持数据库表前缀应该是不少应用中比较常见的功能,而在ABP中并没直接提供这一功能,因此在咱们的应用中,咱们转而借助EF Core的配置来实现数据库表前缀的配置。ide

解决方案

这里我结合了Fluent API和数据注解的形式进行配置。ui

首先,约定全部自定义的表,在其实体类型上都标注了[Table("tablename")]属性。code

而后在QincaiDbContext中重载OnModelCreating方法。htm

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var entityTypes = modelBuilder.Model.GetEntityTypes().ToList();
    // 设置自定义表前缀
    foreach (var entityType in entityTypes)
    {
        if (entityType.ClrType
            .GetCustomAttributes(typeof(TableAttribute), true)
            .FirstOrDefault() is TableAttribute table)
        {
            // 若是你的表名就是实体类型名的话,能够修改成以下形式,就没必要给出[table]的Name参数
            // string tableName = tablePrefix + entityType.ClrType.Name;
            // 如如有其余需求也可在此进行修改
            string tableName = tablePrefix + table.Name;
            modelBuilder.Entity(entityType.ClrType)
                .ToTable(tableName);
        }
    }
    // 设置内置表前缀
    modelBuilder.ChangeAbpTablePrefix<Tenant, Role, User>(tablePrefix);
}

经历

由于采用的Module Zero模板,其数据库上下文中已包含部份内置表,ABP Module Zero也提供了拓展方法ModelBuilder.ChangeAbpTablePrefix<TTenant, TRole, TUser>以便于修改表前缀,其默认的表前缀为Abp对象

剩下就是配置咱们本身定义的表的前缀,这里咱们考虑将表前缀以字符串常量的形式储存。blog

参考资料:EF Core文档文档

若是你喜欢用Fluent API来配置数据库,那么解决方案就很简单了,直接拼接字符串生成新表名便可。字符串

能够参考如下代码:

// 这里tablePrefix为字符串常量
modelBuilder.Entity<Blog>().ToTable(tablePrefix + "Blogs");

可是,若是每个类型都须要配置的话,难免显得有些冗长。所以,我便考虑经过反射的方式来统一配置表前缀。

首先,咱们须要获取到全部的实体类型。

// 这里须要注意须要将迭代对象做临时存储
// 直接foreach的话会报错,即不能修改迭代中的对象
var entityTypes = modelBuilder.Model.GetEntityTypes().ToList();

foreach (var entityType in entityTypes)
{
    // 配置表前缀
    // ...
}

而后即是表前缀的配置,一开始个人想法是直接经过实体类型名来配置表名,但在考虑实际状况后,我认为仍是须要有必定的灵活度使得该解决方案更通用。

最终,这里我选择用数据注解的方式来为指定表名,即利用[Table]特性。

由于,这是EF Core官方所提供配置方式之一,不会让你们由于配置表前缀而增删过多代码。

咱们会用到[Table]特性的Name参数,例如这样:

using System.ComponentModel.DataAnnotations.Schema;

[Table("blogs")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

由于特性并不支持在其参数中引用字符串常量,因此[Table($"{tablePrefix}blogs")]这种写法是不存在的,你们清醒一下。

而后,就是使用Fluent API来配置表前缀了。

// 经过反射获取该实体类上定义的TableAttribute
// 这里没有处理table为null的状况
TableAttribute table = (TableAttribute)entityType.ClrType
    .GetCustomAttributes(typeof(TableAttribute), true)
    .FirstOrDefault();

// 利用TableAttribute中的Name参数来配置表名
modelBuilder.Entity(entityType.ClrType)
    .ToTable(tablePrefix + table.Name);

结合模式匹配语法,咱们能够写出以下形式:

// 若table为null,模式匹配结果将为false
if (entityType.ClrType
    .GetCustomAttributes(typeof(TableAttribute), true)
    .FirstOrDefault() is TableAttribute table)
{
    modelBuilder.Entity(entityType.ClrType)
        .ToTable(tablePrefix + table.Name);
}

最后,尚未完!!

还记得在一开始,我就说了ABP Module Zero内置表有默认的前缀Abp,也就是说在上述反射得到的内置表table.Name将是Abpxxx的形式,若是你不但愿表名中出现Abp,能够在反射以后再使用Abp提供的拓展方法将表名修改一下。

相关文章
相关标签/搜索