1. 程式人生 > 其它 >EF Core3.1 CodeFirst動態自動新增表和欄位的描述資訊

EF Core3.1 CodeFirst動態自動新增表和欄位的描述資訊

前言

我又來啦..

本篇主要記錄如何針對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 在開源化的今天,我們只要願意去多翻翻原始碼,會發現自己可以擴充套件的東西還有很多~很多~

最後..在提一嘴,真心希望國產資料庫的訪問庫 能夠開源.. 畢竟,人多力量大~

又不需要資料庫應用開源..起碼訪問元件 你能開源吧..

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

作者:顧振印 出處:http://www.cnblogs.com/GuZhenYin/ 如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面