欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-02-21 09:17:15
配置数据库表前缀 "ABP踩坑记录 目录" 本篇其实和ABP关系并不大,主要是EF Core的一些应用 . 。 起因 支持数据库表前缀应该是很多应用中比较常见的功能,而在ABP中并没直接提供这一功能,所以在我们的应用中,我们转而借助EF Core的配置来实现数据库表前缀的配置。 解决方案 这里我结合 ......

配置数据库表前缀

abp踩坑记录-目录

本篇其实和abp关系并不大,主要是ef core的一些应用-.-。

起因

支持数据库表前缀应该是很多应用中比较常见的功能,而在abp中并没直接提供这一功能,所以在我们的应用中,我们转而借助ef core的配置来实现数据库表前缀的配置。

解决方案

这里我结合了fluent api和数据注解的形式进行配置。

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

然后在qincaidbcontext中重载onmodelcreating方法。

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

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

参考资料: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提供的拓展方法将表名修改一下。