使用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
及其扩展类库进行研究,下个周末继续研究。