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提供的拓展方法将表名修改一下。
ABP框架入门踩坑-配置数据库表前缀的更多相关文章
- ABP框架入门踩坑-配置User Secrets
配置User Secrets ABP踩坑记录-目录 起因 因为以往习惯在User Secrets中保存连接字符串之类信息,但当我把连接字符串移到secrets.json中后,却发现在迁移过程中会报如下 ...
- ABP框架入门踩坑-添加实体
添加实体 ABP踩坑记录-目录 这里我以问答模块为例,记录一下我在创建实体类过程中碰到的一些坑. 审计属性 具体什么是审计属性我这里就不再介绍了,大家可以参考官方文档. 这里我是通过继承定义好的基类来 ...
- ABP框架入门踩坑-使用MySQL
使用MySQL ABP踩坑记录-目录 起因 因为我自用的服务器只是腾讯云1核1G的学生机,不方便装SQL Server,所以转而MySQL. 这里使用的MySQL版本号为 8.0. 解决方案 删除Qi ...
- ABP框架源码学习之修改默认数据库表前缀或表名称
ABP框架源码学习之修改默认数据库表前缀或表名称 1,源码 namespace Abp.Zero.EntityFramework { /// <summary> /// Extension ...
- 我的微信小程序入门踩坑之旅
前言 更好的阅读体验请:我的微信小程序入门踩坑之旅 小程序出来也有一段日子了,刚出来时也留意了一下.不过赶上生病,加上公司里也有别的事,主要是自己犯懒,就一直没做.这星期一,赶紧趁着这股热乎劲,也不是 ...
- 【ABP框架系列学习】启动配置(5)
ABP提供了在启动时配置模块的基础设施和模型. 1.配置ABP 配置ABP是在模块的PreInitialize方法中完成的,例如: public class SimpleTaskSystemModul ...
- 项目那几步走:先配置setting路径文件、创建数据库、执行数据库迁移命令、配置mysql数据库信息、注册app、注释中间件、pymysql替换mysqldb-配置urls路由-继续视图函数-然后HTML页面展示-HTML里面导入css文件、models配置数据库表、
django使用mysql数据库: 首先cmd创建库 1.settings: """Django settings for day42 project. Generate ...
- Go ORM框架 - GORM 踩坑指南
今天聊聊目前业界使用比较多的 ORM 框架:GORM.GORM 相关的文档原作者已经写得非常的详细,具体可以看这里,这一篇主要做一些 GORM 使用过程中关键功能的介绍,GORM 约定的一些配置信息说 ...
- Spark踩坑记——数据库(Hbase+Mysql)
[TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...
随机推荐
- abp项目中无法使用HttpContext.Current.Session[""]的问题
web项目Global.asax.cs中加入如下代码 public override void Init() { this.PostAuthenticateRequest += (sender, e) ...
- 对象回收过程?线程池执行过程? map原理?集合类关系?synchronized 和 volatile ? 同一个类的方法事务传播控制还有作用吗?java 锁
1. 对象回收过程? 可达性分析算法: 如果一个对象从 GC Roots 不可达时,则证明此对象不可用. 通过一系列称为GC ROOTS的对象作为起点,从这些起点往下搜索,搜索走过的路径 称为引用链 ...
- python 的文件操作
二进制用法 f=open('test.txt','wb') f.write("汉字\r\n".encode('UTF-8')) f.write("hello". ...
- spring4.3.9 @ResponseBody中文乱码,全是问号
<mvc:annotation-driven> <mvc:message-converters register-defaults="true"> < ...
- nginx xxx.conf
server { listen 80 ; server_name xxx.test.cn localhost 127.0.0.1 115.29.96.222; access_log /var/log/ ...
- Vue自定义指令报错:Failed to resolve directive: xxx
Vue自定义指令报错 Failed to resolve directive: modle 这个报错有2个原因: 1.指令单词拼错 2.Vue.directive() 这个方法没有写在 new Vue ...
- 证明LDU分解的唯一性
首先上(下)三角矩阵乘以上(下)三角矩阵结果还是上(下)三角矩阵, 另外我们考虑相乘后的对角元素可发现,对角原始是原来2矩阵对应对角元素的乘积. 另外对角线都是1的上(下)三角矩阵必定可以只是用行运算 ...
- C++ MFC棋牌类小游戏day1
好用没用过C++做一个完整一点的东西了,今天开始希望靠我这点微薄的技术来完成这个小游戏. 我现在的水平应该算是菜鸟中的战斗鸡了,所以又很多东西在设计和技术方面肯定会有很大的缺陷,我做这个小游戏的目的单 ...
- zip / unzip 的用法
zip 1.功能作用:压缩文件或者目录 2.位置:/usr/bin/zip 3.格式用法:zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [z ...
- 20155205 2016-2017-2 《Java程序设计》第8周学习总结
20155205 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 第十四章 NIO使用频道来衔接数据节点,可以设定缓冲区容量,在缓冲区中对感兴趣的数据区块进行 ...