使用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
做爲一個被拋棄的10年neter,對於本身不曾研究過源碼耿耿於懷(其實n年前我研究過jquery的部分源碼,那不算)。所以我毅然下載了EFCore
的源碼。ide
源碼地址:https://github.com/dotnet/efcore.git工具
DatabaseModelFactory
SqlServerDatabaseModelFactory
DatabaseModel
皇天不負有心人:用了一個週末的時間,關於如何添加註釋,我找到了最關鍵地方測試
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模板難以自定義
使用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
及其擴展類庫進行研究,下個週末繼續研究。