前言

我又来啦..

本篇主要记录如何针对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. ThinkPHP 全局异常处理

    wqy的笔记:http://www.upwqy.com/details/273.html 在thinkphp6 和 thinkphp5 全局异常处理 稍有不同 ThinkPHP6 在 tp6 中 框架 ...

  2. Python+Selenium自动化-设置等待三种等待方法

    Python+Selenium自动化-设置等待三种等待方法   如果遇到使用ajax加载的网页,页面元素可能不是同时加载出来的,这个时候,就需要我们通过设置一个等待条件,等待页面元素加载完成,避免出现 ...

  3. Python+Selenium学习笔记10 - send_keys上传文件

    在火狐浏览器上传文件 上传前,同一个HTML文件在火狐和Edge浏览器显示有些不同 这是Firefox浏览器的显示 这是Edge浏览器 上传后 1 # coding = utf-8 2 3 from ...

  4. Single Shot Multibox Detection (SSD)实战(下)

    Single Shot Multibox Detection (SSD)实战(下) 2. Training 将逐步解释如何训练SSD模型进行目标检测. 2.1. Data Reading and In ...

  5. Salesforce LWC学习(三十四) 如何更改标准组件的相关属性信息

    本篇参考: https://www.cnblogs.com/zero-zyq/p/14548676.html https://www.lightningdesignsystem.com/platfor ...

  6. Spring Cloud06: Ribbon 负载均衡

    一.使用背景 前面的学习中,我们已经使用RestTemplate来实现了服务消费者对服务提供者的调用,如果在某个具体的业务场景下,对某个服务的调用量突然大幅提升,这个时候就需要对该服务实现负载均衡以满 ...

  7. 学废了系列 - WebGIS vs WebGL图形编程

    目前工作中有不少涉及到地图的项目,我参加了几次技术评审,前端伙伴们在 WebGIS 方面的知识储备稍有不足,这次分享的主要目的是科普一些在前端领域比较常用的 WebGIS 知识.另外,我之前的工作中积 ...

  8. 【知识点】SQLite3总结

    目录 基本的DDL.DML 创建表,包含日期字段 插入一行,包含日期字段 查找,包含日期字段 查找,按照排序以及限制条目输出 删除记录 更新数据 视图 索引 触发器 事务 专业术语 基本的DDL.DM ...

  9. 使用Spring Data JPA 访问 Mysql 数据库-配置项

    jpa操作数据库 注意:数据库采用的是本机数据库,下面是建表语句及初始化数据: SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------- ...

  10. GitHub Desktop的使用,创建项目、上传文件,设置忽略文件

    下载登陆之后 新建项目File--第一个New repository 然后输入项目名称,选择项目文件夹,最后点Creata repository创建项目 这只是在本地建了项目. 项目文件夹中有其他文件 ...