当前位置: 首页 > news >正文

Day 2 Abp框架下,MySQL数据迁移时,添加表和字段注释

后端采用Abp框架,当前最新版本是7.4.0。

数据库使用MySQL,在执行数据库迁移时,写在Domain层的Entity类上的注释通通都没有,这样查看数据库字段的含义时,就需要对照代码来看,有些不方便。今天专门来解决这个问题。

还是一顿搜索,发现了两个方案:

abp 框架拓展mysql 迁移:增加数据库表和列备注

EFcore+MySql 数据迁移的时候,怎么给表结构加注释?


 

上述两篇文章,

第一篇重载 MySqlMigrationsSqlGenerator 来实现加注释,但是字段注释是通过Description属性来获取的,这样字段上就要注释和Description重复写两遍。

第二篇直接通过工具,读取xml文档,生成 HasComment相关代码,每次都需要手动修改DbContext代码。

都不是特别完美,所以结合一下看看。具体方案还是重载MySqlMigrationsSqlGenerator,但是通过读取xml来获取信息。

首先是SqlGenerator:

/// <summary>
/// 拓展迁移操作:增加数据表和列备注
/// </summary>
public class MyMigrationsSqlGenerator : MySqlMigrationsSqlGenerator
{public MyMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies,IMigrationsAnnotationProvider migrationsAnnotations,ICommandBatchPreparer commandBatchPreparer,IMySqlOptions mySqlOptions): base(dependencies, commandBatchPreparer, mySqlOptions){}protected override void Generate(MigrationOperation operation, IModel model, MigrationCommandListBuilder builder){base.Generate(operation, model, builder);if (operation is CreateTableOperation || operation is AlterTableOperation)CreateTableComment(operation, model, builder);if (operation is AddColumnOperation || operation is AlterColumnOperation)CreateColumnComment(operation, model, builder);}/// <summary>/// 创建表注释/// </summary>/// <param name="operation"></param>/// <param name="builder"></param>private void CreateTableComment(MigrationOperation operation, IModel model, MigrationCommandListBuilder builder){string tableName = string.Empty;string description = string.Empty;if (operation is AlterTableOperation){var t = operation as AlterColumnOperation;tableName = (operation as AlterTableOperation).Name;}if (operation is CreateTableOperation){var t = operation as CreateTableOperation;var addColumnsOperation = t.Columns;tableName = t.Name;foreach (var item in addColumnsOperation){CreateColumnComment(item, model, builder);}}//description = DbDescriptionHelper.GetDescription(tableName.Replace(jingdianConsts.DbTablePrefix, ""));description = GetDescription(tableName, null);if (tableName.IsNullOrWhiteSpace())throw new Exception("表名为空引起添加表注释异常.");var sqlHelper = Dependencies.SqlGenerationHelper;builder.Append("ALTER TABLE ").Append(sqlHelper.DelimitIdentifier(tableName)).Append(" COMMENT ").Append("'").Append(description).Append("'").AppendLine(sqlHelper.StatementTerminator).EndCommand();}/// <summary>/// 创建列注释/// </summary>/// <param name="operation"></param>/// <param name="builder"></param>private void CreateColumnComment(MigrationOperation operation, IModel model, MigrationCommandListBuilder builder){//alter table a1log modify column UUID VARCHAR(26) comment '修改后的字段注释';string tableName = string.Empty;string columnName = string.Empty;string columnType = string.Empty;string description = string.Empty;if (operation is AlterColumnOperation){var t = (operation as AlterColumnOperation);columnType = t.ColumnType;}if (operation is AddColumnOperation){var t = (operation as AddColumnOperation);columnType = t.ColumnType;description = GetDescription(tableName, columnName);}if (columnName.IsNullOrWhiteSpace() || tableName.IsNullOrWhiteSpace() || columnType.IsNullOrWhiteSpace())throw new Exception("列名为空或表名为空或列类型为空引起添加列注释异常." + columnName + "/" + tableName + "/" + columnType);var sqlHelper = Dependencies.SqlGenerationHelper;builder.Append("ALTER TABLE ").Append(sqlHelper.DelimitIdentifier(tableName)).Append(" MODIFY COLUMN ").Append(columnName).Append(" ").Append(columnType).Append(" COMMENT ").Append("'").Append(description).Append("'").AppendLine(sqlHelper.StatementTerminator).EndCommand();}private string GetDescription(string tableName, string? columnName){var type = TableCommentRegister.Types[tableName];if (type == null){return string.Empty;}string xmlPath = type.Module.Name.Replace("dll","xml");XmlDocument xml = new XmlDocument();xml.Load(xmlPath);var classNode = xml.SelectSingleNode(($"//member[@name='T:{type.FullName}']"));if (classNode == null){return string.Empty;}if (columnName == null){return classNode.InnerText.Trim();}else{var propertyNode = xml.SelectSingleNode(($"//member[@name='P:{type.FullName}.{columnName}']"));if (propertyNode == null){return string.Empty;}return propertyNode.InnerText.Trim();}}
}

这里面有一个点,生成Sql时,只知道table name和column name,一般情况下列名就是属性名,可以不考虑,但是表名和类名可能会有差异,比如前后缀之类的。参考1中,就是直接做替换,我考虑还是做了一个静态字典对象,把表名和类名做了一个映射,具体如下:

/// <summary>
/// 数据表注册器
/// </summary>
public static class TableCommentRegister
{public static Dictionary<string, Type> Types { get; set; } = new Dictionary<string, Type>();/// <summary>/// 配置实体对应的数据表,同时注册类型,用于后续生成备注/// </summary>/// <typeparam name="T">实体类型</typeparam>/// <param name="builder"></param>/// <param name="tableName">数据表名</param>public static void ToTableWithComment<T>(this EntityTypeBuilder<T> builder, string tableName) where T : class{builder.ToTable(tableName);Types.TryAdd(tableName, typeof(T));}
}

然后在DbContext类中,针对表的处理代码如下:

 builder.Entity<Company>(b =>{string tableName = Consts.DbTablePrefix + "Company";b.ToTableWithComment(tableName);b.ConfigureByConvention(); //auto configure for the base class props});

就是把之前的 ToTable 改成 ToTableWithComment 就可以了。

最后,需要修改DbSchemaMigrator类,把SqlGenerator注册进去。这里我就简单粗暴的复制了一下DbContextFactory类。因为DbContextFactory代码注释则表明了其只是用于EF Core console commands,在Abp的DbMigrator程序中不起作用。

DbSchemaMigrator类中,Abp 脚手架代码应该是这样的:

public async Task MigrateAsync()
{/* We intentionally resolving the XiuYuanDbContext* from IServiceProvider (instead of directly injecting it)* to properly get the connection string of the current tenant in the* current scope.*/await _serviceProvider.GetRequiredService<XiuYuanDbContext>().Database.MigrateAsync();
}

修改如下:

public async Task MigrateAsync()
{    await CreateDbContext()            .Database.MigrateAsync();
}public xxxDbContext CreateDbContext()
{xxxEfCoreEntityExtensionMappings.Configure();var configuration = BuildConfiguration();var connection = configuration.GetConnectionString(xxxConsts.DbSchema);var builder = new DbContextOptionsBuilder<xxxDbContext>().UseMySql(connection, ServerVersion.AutoDetect(connection), o => o.SchemaBehavior(MySqlSchemaBehavior.Ignore))// 注意这里的ReplaceService.ReplaceService<IMigrationsSqlGenerator, MyMigrationsSqlGenerator>();return new xxxDbContext(builder.Options);
}private static IConfigurationRoot BuildConfiguration()
{var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: false);return builder.Build();
}

至此,所有基础性工作都完成了,后面再添加领域模型时,记得把ToTable改成ToTableWithComment即可。

相关文章:

Day 2 Abp框架下,MySQL数据迁移时,添加表和字段注释

后端采用Abp框架&#xff0c;当前最新版本是7.4.0。 数据库使用MySQL&#xff0c;在执行数据库迁移时&#xff0c;写在Domain层的Entity类上的注释通通都没有&#xff0c;这样查看数据库字段的含义时&#xff0c;就需要对照代码来看&#xff0c;有些不方便。今天专门来解决这个…...

传智教育研究院重磅发布Java学科新研发《智慧养老》项目

在招聘Java开发人才的过程中&#xff0c;企业往往对候选人的项目经验有着严格的要求&#xff0c;项目经验成为顺利就业的重要敲门砖之一。而在数字化技术的学习中&#xff0c;如何让学员通过项目课程有效地积累实战开发经验&#xff0c;就成了数字化技术职业教育的一个重大难点…...

Fiddler抓包VSCode和探索

前言&#xff1a; 最近在使用 VSCode 调试 web 程序时&#xff0c;遇到一些问题&#xff0c;当时不知道如何是好。所以决定抓看来看一看&#xff0c;然后一顿操作猛如虎&#xff0c;成功安装了抓包软件 – Fiddler Classic。我并没有使用 Postman 这种重量级的 HTTP 测试软件&a…...

Pytorch指定数据加载器使用子进程

torch.utils.data.DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue,num_workers4, pin_memoryTrue) num_workers 参数是 DataLoader 类的一个参数&#xff0c;它指定了数据加载器使用的子进程数量。通过增加 num_workers 的数量&#xff0c;可以并行地读取和预处…...

【科普】干货!带你从0了解移动机器人(六) (底盘结构类型)

牵引式移动机器人&#xff08;AGV/AMR&#xff09;&#xff0c;通常由一个牵引车和一个或多个被牵引的车辆组成。牵引车是机器人的核心部分&#xff0c;它具有自主导航和定位功能&#xff0c;可以根据预先设定的路径或地标进行导航&#xff0c;并通过传感器和视觉系统感知周围环…...

爆肝整理,Pytest+Allure+Jenkins自动化测试集成实战(图文详细步骤)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、简介 pytesta…...

微信批量添加好友,让你的人脉迅速增长

在这个数字化时代&#xff0c;微信作为中国最流行的社交平台之一&#xff0c;已经成为了人们生活中不可或缺的一部分。它的广泛使用为我们提供了无限的社交可能性。你是否曾为了扩大人脉圈子而犯愁&#xff1f;今天&#xff0c;我将向你揭示一个高效添加微信好友的秘密武器&…...

3D模型怎么贴法线贴图?

1、法线贴图的原理&#xff1f; 法线贴图&#xff08;normal mapping&#xff09;是一种计算机图形技术&#xff0c;用于在低多边形模型上模拟高多边形模型的细节效果。它通过在纹理坐标上存储和应用法线向量的信息来实现。 法线贴图的原理基于光照模型。在渲染过程中&#x…...

QT中文乱码解决方案与乱码的原因

相信大家应该都遇到过中文乱码的问题&#xff0c;有时候改一改中文就不乱码了&#xff0c;但是有时候用同样的方式还是乱码&#xff0c;那么这个乱码到底是什么原因&#xff0c;又该如何彻底解决呢&#xff1f; 总结 先总结一下&#xff1a; Qt5中&#xff0c;将QString()的构…...

sam9x60 boot

...

3D模型格式转换工具HOOPS Exchange:支持国际标准STEP格式!

HOOPS Exchange SDK是一组C软件库&#xff0c;使开发团队能够快速将可靠的2D和3D CAD导入和导出添加到其应用程序中&#xff0c;访问广泛的数据&#xff0c;包括边界表示 (B-REP)、产品制造信息 (PMI)、模型树、视图、持久 ID、样式、构造几何、可视化等&#xff0c;无需依赖任…...

java--死循环与循环嵌套

1.死循环 可以一直执行下去的一种循环&#xff0c;如果没有干预不会停下来的 2.死循环的写法 3.循环嵌套 循环中又包含循环 4.循环嵌套的特点 外部循环每循环一次&#xff0c;内部循环会全部执行完一轮...

基于机器视觉的图像拼接算法 计算机竞赛

前言 图像拼接在实际的应用场景很广&#xff0c;比如无人机航拍&#xff0c;遥感图像等等&#xff0c;图像拼接是进一步做图像理解基础步骤&#xff0c;拼接效果的好坏直接影响接下来的工作&#xff0c;所以一个好的图像拼接算法非常重要。 再举一个身边的例子吧&#xff0c;…...

基于arduino uno + L298 的直流电机驱动proteus仿真设计

一、L298简介&#xff1a; L298是一个集成的单片电路&#xff0c;采用15个导线多瓦和PowerSO20封装。它是一个高电压、高电流双全桥驱动器&#xff0c;旨在接受标准TTL逻辑电平和驱动感应负载&#xff0c;如继电器、螺线管、直流和加速电机。提供两个使输入来使独立于输入信号的…...

cola架构:有限状态机(FSM)源码分析

目录 0. cola状态机简述 1.cola状态机使用实例 2.cola状态机源码解析 2.1 语义模型源码 2.1.1 Condition和Action接口 2.1.2 State 2.1.3 Transition接口 2.1.4 StateMachine接口 2.2 Builder模式 2.2.1 StateMachine Builder模式 2.2.2 ExternalTransitionBuilder-…...

通信仿真软件SystemView安装教程(超详细)

介绍 system view是一种电子仿真工具。它是一个信号级的系统仿真软件&#xff0c;主要用于电路与通信系统的设计和仿真&#xff0c;是一个强有力的动态系统分析工具&#xff0c;能满足从数字信号处理&#xff0c;滤波器设计&#xff0c;直到复杂的通信系统等不同层次的设计&am…...

Go学习第八章——面向“对象”编程(入门——结构体与方法)

Go面向“对象”编程&#xff08;入门——结构体与方法&#xff09; 1 结构体1.1 快速入门1.2 内存解析1.3 创建结构体四种方法1.4 注意事项和使用细节 2 方法2.1 方法的声明和调用2.2 快速入门案例2.3 调用机制和传参原理2.4 注意事项和细节2.5 方法和函数区别 3 工厂模式 Gola…...

「滚雪球学Java」:方法函数(章节汇总)

&#x1f3c6;本文收录于「滚雪球学Java」专栏&#xff0c;专业攻坚指数级提升&#xff0c;助你一臂之力&#xff0c;带你早日登顶&#x1f680;&#xff0c;欢迎大家关注&&收藏&#xff01;持续更新中&#xff0c;up&#xff01;up&#xff01;up&#xff01;&#xf…...

数据分析必备原理思路(二)

文章目录 三、主流的数据分析方法与框架使用1. 五个数据分析领域关键的理论基础&#xff08;1&#xff09;大数定律&#xff08;2&#xff09;罗卡定律&#xff08;3&#xff09;幸存者偏差&#xff08;4&#xff09;辛普森悖论&#xff08;5&#xff09;帕累托最优&#xff08…...

分布式ID系统设计(1)

分布式ID系统设计(1) 在分布式服务中&#xff0c;需要对data和message进行唯一标识。 比如订单、支付等。然后在数据库分库分表之后也需要一个唯一id来表示。 基于DB的自增就肯定不能满足了。这个时候能够生成一个Global的唯一ID的服务就很有必要我们姑且把它叫做id-server 。…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

DBLP数据库是什么?

DBLP&#xff08;Digital Bibliography & Library Project&#xff09;Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高&#xff0c;数据库文献更新速度很快&#xff0c;很好地反映了国际计算机科学学术研…...