EFCore Database-first深刻研究

EFCore Database-first深刻研究

使用Scaffold-DbContext從數據庫生成實體jquery

說明文檔:

關於 Scaffold-DbContext 微軟有官方說明文檔git

https://docs.microsoft.com/zh-cn/ef/core/miscellaneous/cli/powershellgithub

實踐:

不妨本身找一個現有的數據庫試一試:sql

LocalDBshell

Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables "Blog","Post" -ContextDir Context -Context BlogContext

MySql數據庫

Scaffold-DbContext "server=127.0.0.1;Port=3306;database=zejedb;uid=root;pwd=123456;Convert Zero Datetime=True;Allow Zero Datetime=True;Charset=utf8;Default Command Timeout =30000;" Pomelo.EntityFrameworkCore.Mysql -OutputDir Models -DataAnnotations

路漫漫

可是經過上述步驟生成的實體,跟本身想要的仍是有那麼一丟丟差距。api

  • 好比我想經過數據庫表註釋、字段註釋,給實體、屬性加上註釋貌似就沒辦法實現。
  • 好比我想統一繼承基類,將建立時間、修改時間、建立人、修改人、Id放到基類,貌似也沒辦法實現。

做爲一個被拋棄的10年neter,對於本身不曾研究過源碼耿耿於懷(其實n年前我研究過jquery的部分源碼,那不算)。所以我毅然下載了EFCore的源碼。ide

源碼地址:https://github.com/dotnet/efcore.git工具

研究EFCore的源碼

以Scaffold-DbContext做爲突破口:

  • 後來又看到這麼幾個類:
    • DatabaseModelFactory
    • SqlServerDatabaseModelFactory
    • DatabaseModel
  • 還下載了Pomelo.EntityFrameworkCore.MySql的源碼
  • 等等

皇天不負有心人:用了一個週末的時間,關於如何添加註釋,我找到了最關鍵地方測試

CSharpEntityTypeGenerator

只要重寫(Override)此類的GenerateClass,GenerateProperties兩個虛擬方法即可

吐槽&繼續(痛苦並快樂着)

微軟的攻城獅細節怎麼就不處理好呢?

public class CSharpEntityTypeGenerator : ICSharpEntityTypeGenerator
    {
        private readonly ICSharpHelper _code;

        private IndentedStringBuilder _sb = null!;
        private bool _useDataAnnotations;

關鍵方法:

public virtual string WriteCode(IEntityType entityType, string @namespace, bool useDataAnnotations)
        {
            Check.NotNull(entityType, nameof(entityType));
            Check.NotNull(@namespace, nameof(@namespace));

            _sb = new IndentedStringBuilder();
            _useDataAnnotations = useDataAnnotations;

            _sb.AppendLine("using System;");
            _sb.AppendLine("using System.Collections.Generic;");

            if (_useDataAnnotations)
            {
                _sb.AppendLine("using System.ComponentModel.DataAnnotations;");
                _sb.AppendLine("using System.ComponentModel.DataAnnotations.Schema;");
            }

            foreach (var ns in entityType.GetProperties()
                .SelectMany(p => p.ClrType.GetNamespaces())
                .Where(ns => ns != "System" && ns != "System.Collections.Generic")
                .Distinct()
                .OrderBy(x => x, new NamespaceComparer()))
            {
                _sb.AppendLine($"using {ns};");
            }

            _sb.AppendLine();
            _sb.AppendLine($"namespace {@namespace}");
            _sb.AppendLine("{");

            using (_sb.Indent())
            {
                GenerateClass(entityType);
            }

            _sb.AppendLine("}");

            return _sb.ToString();
        }

生成實體全然靠WriteCode方法,爲何sb不公開?(後來才知道,他們合併代碼有這麼一個校驗:Public_inheritable_apis_should_be_virtual)
無奈之下,我把整個類都拷貝出來,稍微修改,添加上關鍵代碼

  • 類註釋:
var comment = entityType.FindAnnotation("Relational:Comment");
if (comment != null && comment.Value != null)
{
    _sb.AppendLine("///<summary>");
    _sb.AppendLine("///" + comment.Value.ToString());
    _sb.AppendLine("///</summary>");
}
  • 實體註釋:
var comment = property.FindAnnotation("Relational:Comment");
if (comment != null && comment.Value != null)
{
    _sb.AppendLine("///<summary>");
    _sb.AppendLine("///" + comment.Value.ToString());
    _sb.AppendLine("///</summary>");
}
  • 測試結果:
總結

生成實體的工具那麼多,何須糾纏Scaffold-DbContext不放手?
其實:
一、我的有代碼潔癖。
二、有代碼註釋強迫症。
三、給本身找個強迫本身看源碼的理由。

其實實現自動生成代碼並帶上註釋的,我的已經有實現的辦法,可是不完美,有些地方仍是須要手動修改。糾纏Scaffold-DbContext是另一種嘗試罷了。

放棄Scaffold-DbContext,使用T4模板

爲什麼放棄

難以自定義

  • 沒法帶註釋(上述幾行代碼已在github上推送了),不過Scaffold-DbContext要支持註釋估計是猴年馬月的事情了。
  • 不知道怎麼繼承基類等

PackageReferences在T4模板下的水土不服

使用CopyLocalLockFileAssemblies,將dll複製到bin目錄下

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>
  <ItemGroup>
  </ItemGroup>
</Project>

T4模板中引用DLL

<#@ assembly name="$(TargetDir)\Microsoft.EntityFrameworkCore.dll" #>
<#@ assembly name="$(TargetDir)\Microsoft.EntityFrameworkCore.Design.dll" #>

其實本人以前是使用本身寫的Zeje.T4_.dll來生成的,如今計劃基於Microsoft.EntityFrameworkCore.dll及其擴展類庫進行研究,下個週末繼續研究。

相關文章
相關標籤/搜索