前言

我又来啦..

本篇主要记录如何针对CodeFirst做自动添加描述的扩展

为什么要用这个呢.. 因为EF Core3.1 CodeFirst 对于自动添加描述这块 只有少部分的数据库支持..

然而我们的客户大佬们 对这个又有要求..所以..没办法 只能自己扩展~

当然也可以根据这个原理来做一些有意思的扩展~

本文就以不支持的达梦数据库来举个栗子

.(PS:真心希望达梦数据库能开放EF Core相关的源码,这样我们也好提交点贡献,国产数据库还是不能太过敝帚自珍阿..)

正文

1.通过扩展生成器,来实现动态自动添加描述信息

我们知道在SQL Server中,可以通过Fluent API来添加针对表或者字段的描述,如下:

builder.Property(prop.Name)
.HasComment("XXX字段描述");

然而在达梦的上下文中,我们如果这样写..是没任何效果的..不用想,肯定是达梦的开发商没写(很多扩展类都缺斤少两)..

那就需要我们自己扩展了, 所以就少不了翻看EF Core源码..

我们通过翻看源码,可以找到MigrationsSqlGenerator这个类. 类名翻译过来,喔唷,这不就是迁移SQL生成器么

那么我们就需要去实现他啦.首先,我们找到达梦实现他的子类:DmMigrationsSqlGenerator

通过反编译,我们发现,果然他并没实现对于Comment属性的代码,那么我们就需要自行扩展

我们添加MyDmigrationsSqlGenerator类继承DmMigrationsSqlGenerator 添加扩展代码如下:

  1 using Microsoft.EntityFrameworkCore.Metadata;
2 using Microsoft.EntityFrameworkCore.Migrations;
3 using Microsoft.EntityFrameworkCore.Migrations.Operations;
4 using System;
5 using System.Collections.Generic;
6 using System.Diagnostics.CodeAnalysis;
7 using System.Linq;
8 using System.Text;
9
10 namespace Ciac.ZTBExpert.Model
11 {
12 public class MyDmigrationsSqlGenerator : DmMigrationsSqlGenerator
13 {
14 public MyDmigrationsSqlGenerator([NotNull] MigrationsSqlGeneratorDependencies dependencies, [NotNull] IMigrationsAnnotationProvider migrationsAnnotations)
15 : base(dependencies, migrationsAnnotations)
16 {
17
18 }
19
20 protected override void Generate(
21 CreateTableOperation operation,
22 IModel model,
23 MigrationCommandListBuilder builder,
24 bool terminate)
25 {
26 base.Generate(operation, model, builder, terminate);
27 var comment = operation.Comment;
28 if (comment != null)
29 {
30 if (terminate)
31 {
32 builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
33 EndStatement(builder);
34 }
35 builder
36 .Append("COMMENT ON TABLE ")
37 .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name, operation.Schema))
38 .Append(" IS ")
39 .Append($"'{comment}'")
40 .Append(Dependencies.SqlGenerationHelper.StatementTerminator);
41 }
42 // Comments on the columns
43 foreach (var columnOp in operation.Columns.Where(c => c.Comment != null))
44 {
45 var columnComment = columnOp.Comment;
46 // builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
47 EndStatement(builder);
48 builder
49 .Append("COMMENT ON COLUMN ")
50 .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name, operation.Schema))
51 .Append('.')
52 .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(columnOp.Name))
53 .Append(" IS ")
54 .Append($"'{columnComment}'")
55 .Append(Dependencies.SqlGenerationHelper.StatementTerminator);
56 }
57 builder.EndCommand();
58 }
59
60
61 protected override void Generate(AlterColumnOperation operation, IModel model, MigrationCommandListBuilder builder)
62 {
63 base.Generate(operation, model, builder);
64 // Comment
65 var oldComment = operation.OldColumn.Comment;
66 var newComment = operation.Comment;
67
68 if (oldComment != newComment)
69 {
70 //builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
71
72 builder
73 .Append("COMMENT ON COLUMN ")
74 .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Table, operation.Schema))
75 .Append('.')
76 .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name))
77 .Append(" IS ")
78 .Append($"'{newComment}'")
79 .Append(Dependencies.SqlGenerationHelper.StatementTerminator);
80 builder.EndCommand();
81 }
82
83 }
84
85 protected override void Generate(AddColumnOperation operation, IModel model, MigrationCommandListBuilder builder, bool terminate)
86 {
87 base.Generate(operation, model, builder, terminate);
88 // Comment
89 var newComment = operation.Comment;
90
91 if (!string.IsNullOrEmpty(newComment))
92 {
93 // builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
94 builder
95 .Append("COMMENT ON COLUMN ")
96 .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Table, operation.Schema))
97 .Append('.')
98 .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name))
99 .Append(" IS ")
100 .Append($"'{newComment}'")
101 .Append(Dependencies.SqlGenerationHelper.StatementTerminator);
102 if (terminate)
103 {
104 EndStatement(builder);
105 }
106 builder.EndCommand();
107
108 }
109
110 }
111 protected override void Generate([NotNull] AlterTableOperation operation, IModel? model, [NotNull] MigrationCommandListBuilder builder)
112 {
113 base.Generate(operation, model, builder);
114 // Comment
115 var oldComment = operation.OldTable.Comment;
116 var newComment = operation.Comment;
117
118 if (oldComment != newComment)
119 {
120
121 EndStatement(builder);
122
123 builder
124 .Append("COMMENT ON TABLE ")
125 .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name, operation.Schema))
126 .Append(" IS ")
127 .Append($"'{newComment}'")
128 .Append(Dependencies.SqlGenerationHelper.StatementTerminator);
129 builder.EndCommand();
130 }
131 }
132 }
133 }

因为我们只是想在创建或者修改表后添加描述.

所以,我们只需要针对CreateTable,AlterColumn,AddColumn,AlterTable 四个生成方法做重写就好了

这样,我们就可以通过在上下文中配置Fluent API就可以自动生成描述了~

我们在EF上下文的OnModelCreating添加代码如下:

 protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<tab_zjcq_ggxx>(a => a.Property("aaa").HasComment("88888"));
}

执行迁移语句Script-Migration

结果如下:

ALTER TABLE "tab_zjcq_ggxx" MODIFY "aaa" NVARCHAR2(50) NULL;

/COMMENT ON COLUMN "tab_zjcq_ggxx"."aaa" IS '8888';

2.通过添加Description特性来优化代码风格,方便管理

虽然上面第一步就已经实现了我们的要求,但是我们发现,通过Fluent API 来添加描述,代码可读性会很差,

且一旦表多起来,那么OnModelCreating 方法就会变的超长(虽然也可以写在实体类里面,但是就觉得很麻烦)..

那么能不能像[MaxLength(50)] 这种特性一样,直接在字段上加个特性来解决这个事情呢?~

当然是可以的啦~

我们修改OnModelCreating 中的代码如下:

        protected override void OnModelCreating(ModelBuilder modelBuilder)
{ var ddd= modelBuilder.Model.GetEntityTypes().ToList();
foreach (var item in ddd)
{
var tabtype = Type.GetType(item.ClrType.FullName);
var props = tabtype.GetProperties();
var descriptionAttrtable = tabtype.GetCustomAttributes(typeof(DescriptionAttribute), true);
if (descriptionAttrtable.Length > 0)
{
modelBuilder.Entity(item.Name).HasComment(((DescriptionAttribute)descriptionAttrtable[0]).Description);
}
foreach (var prop in props)
{
var descriptionAttr = prop.GetCustomAttributes(typeof(DescriptionAttribute), true);
if (descriptionAttr.Length>0)
{
modelBuilder.Entity(item.Name).Property(prop.Name).HasComment(((DescriptionAttribute)descriptionAttr[0]).Description);
}
}
} }

这里通过反射,得到包含DescriptionAttribute特性的字段,然后读取描述信息,通过HasComment 自动添加~

然后我们给字段添加描述如下:

执行迁移语句Script-Migration~

我们会发现,描述已经自动生成啦~

结束语

其实不管是.NET 5.0 还是EF Core 在开源化的今天,我们只要愿意去多翻翻源码,会发现自己可以扩展的东西还有很多~很多~

最后..在提一嘴,真心希望国产数据库的访问库 能够开源.. 毕竟,人多力量大~

又不需要数据库应用开源..起码访问组件 你能开源吧..

好了..就到这了 瑞思拜~

EF Core3.1 CodeFirst动态自动添加表和字段的描述信息的更多相关文章

  1. sql server 获取数据字段(表的字段和类型信息)

    获取数据字段(表的字段和类型信息) SELECT 表名= then d.name else '' end, 表说明= then isnull(f.value,'') else '' end, 字段序号 ...

  2. sublime 设置新建文件自动添加author(作者)等文件头信息

    很多时候, sublime 自带自动添加文件头信息, 但是并不是我们想要比如下面这样的:新建一个python文件 自动添加的author 信息== 上面并不是我想要的, 我想要下面这样的效果:== 这 ...

  3. 【JDBC】仅输入表名和要插入的记录数,自动检测表的字段和类型,然后插入数据的全自动程序(Oracle版)

    之前写的批量插值程序只是五六半自动版本,因为表的字段还需要手工填写,这回只要指定表名和要插多少数据就行了,类似于全自动突击步枪,扣动扳机就把字段打完为止. 全自动程序如下,诸位拿下去后可以修改成自己想 ...

  4. sqlserver添加表、字段注释

    引用 :http://begoodluck.blog.163.com/blog/static/20450728020141191412788/ 1.sqlserver用语句给表注释EXECUTE sp ...

  5. 如何在Pycharm中自动添加时间日期、作者等信息

    参考下面的内容 #_author_='Lucky';#date: ${DATE}

  6. sqlserver 获取所有表的字段类型等信息

    USE [MultipleAnalysisDataFY] GO /****** Object: View [dbo].[selectfieldtype] Script Date: 2018/11/7 ...

  7. MS Sql添加描述信息 及其他信息

    --查询某个表的描述 SELECT * FROM fn_listextendedproperty (NULL, 'user', 'dbo', 'table', '(表名)',NULL, NULL) - ...

  8. eclipse自动添加作者、日期等注释

    使用eclipse的时候一般会添加自己的注释,标注日期作者等内容,我总结的添加注释的方式有两种:一.在新建class时自动添加注释:二.通过快捷键自动添加注释.下面分别描述一下添加方式. 一.新建cl ...

  9. [转载]PyCharm创建.py自动添加文件头注释

    转自:https://blog.csdn.net/qq_36482772/article/details/67218214 创建.py文件时 顺便自动添加作者.时间.文件名信息…… mac系统打开编辑 ...

随机推荐

  1. 快成物流科技 x mPaaS | 小程序容器加持下的技术架构“提质增效”

      导言 从 2017 年开始,GMTC"移动技术大会"就更名为"大前端技术大会".发展至今,混合开发.原生开发.前端开发等概念正在深度融合,组成"大 ...

  2. java IO教程《三》

    缓冲区流讲解(Buffered) 什么是缓冲区? 缓冲流,也叫高效流,是对4个基本的File流的增强,所以也是4个流,按照数据类型分类: 字节缓冲流:BufferedInputStream,Buffe ...

  3. Google Hacking 搜索引擎攻击与防范

    Google Hacking,有时也会被称为 Google dorking,是一种利用谷歌搜索的高级使用方式进行信息收集的技术.这个概念最早在2000年由黑客 Johnny Long 提出并推广,一系 ...

  4. THINKPHP_(1)_修改TP源码,支持对中文字符串按拼音进行排序。

    问题:TP从服务器数据中取出的collection数据,当进一步在网页中进行分页显示时,需要调用order函数,实现类似如下图的排序. 当点击页面中的相关内容时,实现对服务器数据进行重排,就要调用TP ...

  5. 摄像头ISP系统原理(中)

    摄像头ISP系统原理(中) AF(FOCUS)----自动对焦 根据光学知识,景物在传感器上成像最清晰时处于合焦平面上.通过更改 LENS 的位置,使得景物在传感器上清晰的成像,是 ISP FOCUS ...

  6. Tensor Core技术解析(下)

    Tensor Core技术解析(下) 让FP16适用于深度学习 Volta的深度学习能力是建立在利用半精度浮点(IEEE-754 FP16)而非单精度浮点(FP32)进行深度学习训练的基础之上. 该能 ...

  7. 编译器架构Compiler Architecture(下)

    编译器架构Compiler Architecture(下) Combining Scanning and Parsing 实际上没有必要将扫描(词法分析/标记化)与解析(语法分析/树生成)分开.基于P ...

  8. .NET平台系列30:.NET Core/.NET 学习资源汇总

    系列目录     [已更新最新开发文章,点击查看详细] .NET Core/.NET技术虽然吸取了.NET Framework 中的精华,但是也扩展了一些新功能,尤其是跨平台的 ASP.NET Cor ...

  9. vue3.0搭建项目

    安装node.js 查看版本node -v 安装vue3.0版本之前需要先把vue-cli升级到4.0版本, 如果之前安装过vue-cli需要把2.0相关的卸载之后重新安装,npm uni -g vu ...

  10. 不下软件,照样可以完美正确格式化树莓派SD卡!(恢复U盘/SD卡到满容量)

    树莓派作用千千万,系统崩溃的理由也数不胜数(不要问我为啥知道),所以系统的重装和sd卡的格式化也在所难免.顺便给大家看一下我今天的成果,我不就是不小心摔了一下我的树莓派...我和sd卡一定是冤家! 捡 ...