FreeSql.Generator命令行代码生成器是如何实现的

目录

  • FreeSql介绍

  • FreeSql.Generator

  • RazorEngine.NetCore

  • 源码解析

  • FreeSql.Tools

FreeSql

FreeSql 是功能强大的对象关系映射技术(O/RM),支持 .NETCore 2.1+ 或 .NETFramework 4.0+ 或 Xamarin。

有一个强大的ORM,也方便我们开发一个代码生成器。

一般情况下,我们开发数据库相关的应用,主要分为三种code first、db first、model first

我只用过前二种,

  • code first,代码优先,数据库都是根据实体类生成,所有的关系,可以是逻辑关联,也可以是物理关联。

  • DB First: 数据库优先,直接设计表结构,用设计工具生成表,设计主键,外键、索引,关联关系等。

当我们使用DB First时,设计好的数据库,我们怎么生成这些实体类、通用的代码、控制器、服务层、Dto呢。今天我来给大家介绍一下FreeSql项目中的一些工具。当然,不使用此ORM的小伙伴也能使用此工具,因为他是通用。

FreeSql.Generator 命令行方式

通过几行命令,就可实现生成项目中通用的代码结构,不需要复制一段代码后修改,加快开发速度,减少重复劳动,少用一根头发。

由于每个人的项目结构,代码位置各不相同,对于ORM来说,不同的业务逻辑各不相同,所以该项目没有相应的模板,相信使用过Razor的同学一定能实现自己的模板。

1-2年前,我和一个学长也写过代码生成器,这里分享一下当时做项目时的一些模板,https://github.com/i542873057/SJNScaffolding/tree/master/SJNScaffolding.RazorPage/Templates,该项目是基于 . NET Core+Razor Page,由于已离职,所以没有继续维护,这些模板都和ABP相关,当时提取了一些通用的功能,单表操作,可以直接生成前后端功能,只需要在word中按统一的格式写好数据字典的文档,直接复制到系统,即可根据空格,定义类型等方式解析字段。

回到FreeSql.Generator 命令行

  • 对于此工具的使用可参考 https://github.com/dotnetcore/FreeSql/wiki/DbFirst

  • 源码位置 https://github.com/dotnetcore/FreeSql/tree/master/Extensions/FreeSql.Generator

  • 前提是本地安装了.net core 3.1 的sdk.

怎么使用呢。

  1. 安装 dotnet-tool 生成实体类

dotnet tool install -g FreeSql.Generator
  1. 新建目录,在地址栏输入 cmd 快速打开命令窗口,输入命令:

FreeSql.Generator --help

我们可以看到

C:\Users\igeekfan\Desktop\code>FreeSql.Generator --help____                   ____         __/ __/  ____ ___  ___   / __/ ___ _  / // _/   / __// -_)/ -_) _\ \  / _ `/ / //_/    /_/   \__/ \__/ /___/  \_, / /_//_/# Github # https://github.com/2881099/FreeSql v1.5.0使用 FreeSql 快速生成数据库的实体类更新工具:dotnet tool update -g FreeSql.Generator# 快速开始 #> FreeSql.Generator -Razor 1 -NameOptions 0,0,0,0 -NameSpace MyProject -DB "MySql,Data Source=127.0.0.1;..."-Razor 1                  * 选择模板:实体类+特性-Razor 2                  * 选择模板:实体类+特性+导航属性-Razor "d:\diy.cshtml"    * 自定义模板文件-NameOptions              * 总共4个布尔值,分别对应:# 首字母大写# 首字母大写,其他小写# 全部小写# 下划线转驼峰-NameSpace                * 命名空间-DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=数据库;Charset=utf8;SslMode=none;Max pool size=2"-DB "SqlServer,Data Source=.;Integrated Security=True;Initial Catalog=数据库;Pooling=true;Max Pool Size=2"-DB "PostgreSQL,Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=数据库;Pooling=true;Maximum Pool Size=2"-DB "Oracle,user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2"-DB "Sqlite,Data Source=document.db"-DB "Dameng,server=127.0.0.1;port=5236;user id=2user;password=123456789;database=2user;poolsize=2"Dameng 是国产达梦数据库-Filter                   Table+View+StoreProcedure默认生成:表+视图+存储过程如果不想生成视图和存储过程 -Filter View+StoreProcedure-Match                    正则表达式,只生成匹配的表,如:dbo\.TB_.+-FileName                 文件名,默认:{name}.cs-Output                   保存路径,默认为当前 shell 所在目录推荐在实体类目录创建 gen.bat,双击它重新所有实体类
  • 更新命令行

dotnet tool update -g FreeSql.Generator
  1. 这里lin-cms-dotnetcore这个项目来测试。

  • 数据库表名是下划线,字段也是下划线方式。

  • -Razor 指定 第一个模板

  • -NameOptions 0,0,0,1 最后一个1,代表 下划线转驼峰,满足C#命名规则

  • -NameSpace 指定了命名空间 LinCms.Core.Entities

  • -DB 就是数据库的相关配置

  • mysql 本地地址 127.0.0.1 3306端口 用户名 root 密码123456 数据库 lin-cms

  • -Match book 这样就能只生成book,支持正则表达式,如 -Math lin_user 就会生成以lin_user开头的表。如dbo.TB_.+,会生成以TB开头的表。即只生成匹配的表

  1. 执行此命令。

FreeSql.Generator -Razor 1  -NameOptions 0,0,0,1 -NameSpace LinCms.Core.Entities -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=123456;Initial Catalog=lincms;Charset=utf8;SslMode=none;Max pool size=2"

这时候代码已经生成了

其中一个代码 生成如下。这些类是partial ,熟悉C#的同学,应该知道,类的定义使用此关键字,我们能在不同的地方为该类扩展。以防止重新同步数据库的结构时,丢失改动的字段。

namespace LinCms.Core.Entities {[JsonObject(MemberSerialization.OptIn), Table(Name = "book")]public partial class Book {/// <summary>/// 主键Id/// </summary>[JsonProperty, Column(Name = "id", IsPrimary = true, IsIdentity = true)]public long Id { get; set; }[JsonProperty, Column(Name = "author", DbType = "varchar(20)")]public string Author { get; set; } = string.Empty;[JsonProperty, Column(Name = "image", DbType = "varchar(50)")]public string Image { get; set; } = string.Empty;//更多xxx}}
  • 最终效果图如下

此时会生成二个文件 __重新生成.bat,下次重新点击他就能重新生成实体类了。

FreeSql.Generator -Razor "__razor.cshtml.txt" -NameOptions 1,1,0,1 -NameSpace MyProject -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=123456;Initial Catalog=lincms;Charset=utf8;SslMode=none;Max pool size=2" -FileName "{name}.cs"

上面的命令-Razor 指定了这个txt文件 __razor.cshtml.txt

我们可以定义自己的模板,以生成符合自已业务的的代码,从而实现快速开发。

我们可以看下模板中的文件内容,他就是asp.net下的mvc 结构下的razor后端模板渲染,把这个.txt后缀去掉,就很明了了。对于asp.net mvc的razor,我们可以将控制器下方法的值替换掉cshtml中的值。这个过程是有一个类库在帮我们实现的,叫RazorEngine,不过那个是.net framework下的实践。.NET Framework 下的RazorEngine代码生成介绍

@using FreeSql.DatabaseModel;@{
var gen = Model as RazorModel;Func<string, string> GetAttributeString = attr => {if (string.IsNullOrEmpty(attr)) return null;return string.Concat(", ", attr.Trim('[', ']'));
};
Func<DbColumnInfo, string> GetDefaultValue = col => {if (col.CsType == typeof(string)) return " = string.Empty;";return "";
};
}
//xxx
namespace @gen.NameSpace {@if (string.IsNullOrEmpty(gen.table.Comment) == false) {@:/// <summary>@:/// @gen.table.Comment.Replace("\r\n", "\n").Replace("\n", "\r\n		/// ")@:/// </summary>
}[JsonObject(MemberSerialization.OptIn)@GetAttributeString(gen.GetTableAttribute())]public partial class @gen.GetCsName(gen.FullTableName) {@foreach (var col in gen.columns) {if (string.IsNullOrEmpty(col.Coment) == false) {@:/// <summary>@:/// @col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n		/// ")@:/// </summary>}@:@("[JsonProperty" + GetAttributeString(gen.GetColumnAttribute(col)) + "]")@:public @gen.GetCsType(col) @gen.GetCsName(col.Name) { get; set; }@GetDefaultValue(col)
@:}}
@gen.GetMySqlEnumSetDefine()
}

RazorEngine.NetCore

到了.NET Core时代,我看了下FreeSql.Generator用的这个类库RazorEngine.NetCore,实现动态操作cshtml,生成需要的文本。

Razor Engine是基于微软Razor解析的模板引擎,它允许你使用Razor语法构建动态模板,你只需要使用Engine的静态方法,Engine.Razor.RunCompile等。

创建一个控制台应用,然后安装包。

Install-Package RazorEngine.NetCore
using RazorEngine;
using RazorEngine.Templating; // For extension methods.string template = "Hello @Model.Name, welcome to RazorEngine!";
var result = Engine.Razor.RunCompile(template, "templateKey", null, new { Name = "World" });Console.WriteLine(result);
  • 输出如下内容

Hello World, welcome to RazorEngine!

此处使用的RunCompile方法是扩展方法,您需要引用RazorEngine.Templating命名空间。

The "templateKey" 保持唯一值,比如使用guid值。字符串,并且你可以根据此字符串key重新运行缓存的模板。

如果再次根据此key,可使用原本的模板。

var result = Engine.Razor.Run("templateKey", null, new { Name = "Max" });
  • 会输出如下内容

Hello Max, welcome to RazorEngine!

上面中的RunCompile第三个参数,传null,因为我们第四个参数使用的是匿名类,

根目录创建一个HelloWord.cshtml,要选择属性,->如果较新则复制 内容,

Hello @Model.Name, welcome to RazorEngine!

控制台如下代码。

string templateFilePath = "HelloWorld.cshtml";
var templateFile = File.ReadAllText(templateFilePath);
string templateFileResult = Engine.Razor.RunCompile(templateFile, Guid.NewGuid().ToString(), null, new
{Name = "World"
});Console.WriteLine(templateFileResult);
  • 控制台输出

Hello World, welcome to RazorEngine!
  • 使用强类型 CopyRightUserInfo.cs生成一个版权所有

using System;
namespace OvOv.Razor
{public class CopyRightUserInfo{public string UserName { get; set; }public string EmailAddress { get; set; }public DateTime CreateTime { get; set; }public string FileRemark { get; set; }}}

根目录创建一个CopyRightTemplate.cshtml,要选择属性,->如果较新则复制 内容,

@{var gen = Model as OvOv.Razor.CopyRightUserInfo;
}
//=============================================================
// 创建人:            @gen.UserName
// 创建时间:          @gen.CreateTime
// 邮箱:             @gen.EmailAddress
//==============================================================

控制台如下代码。

string copyRightTemplatePath = "CopyRightTemplate.cshtml";
var copyRightTemplate = File.ReadAllText(copyRightTemplatePath);
string copyRightResult = Engine.Razor.RunCompile(copyRightTemplate, Guid.NewGuid().ToString(), typeof(CopyRightUserInfo), new CopyRightUserInfo
{CreateTime = DateTime.Now,EmailAddress = "710277267@qq.com",UserName = "IGeekFan"
});
Console.WriteLine(copyRightResult);Console.ReadKey();
  • 控制台输出

//=============================================================
// 创建人:            IGeekFan
// 创建时间:          2020/6/23 18:14:08
// 邮箱:             710277267@qq.com
//==============================================================

全放到控制台下,输出如下结果。代码生成器最重要的一点解决了,我们就能实现自己的代码生成器,先构建自己的模板,实现输入(命令行,WPF,WEB端及更多),输出(生成文件)。

  • 以上源码已放到示例代码中 https://github.com/luoyunchong/dotnetcore-examples/blob/master/aspnetcore-freesql/OvOv.Razor/Program.cs

源码解析

首先这是一个控制台应用,Main(string[] args)可接收多个参数。

  1. 处理无参数,--help

  2. 处理args数组,解析出所有的参数,如果没有设置,则为默认值。(处理一些参数异常问题)最重要的是根据-Razor,选定对应的模板。

ArgsRazor=""//根据-Razor  1 不是2 还是模板的路径,取出的模板文本值。
var razorId = Guid.NewGuid().ToString("N");
RazorEngine.Engine.Razor.Compile(ArgsRazor, razorId);
  1. 根据数据库连接串,取出参数过滤后的表,视图,存储过程

  2. 循环数据库的表等,

  • model为模板中需要的数据

  • razorId与上文的razorId相同,

  • sw为生成后的文本保存的值。

var sw = new StringWriter();
var model = new RazorModel(fsql, ArgsNameSpace, ArgsNameOptions, tables, table);
RazorEngine.Engine.Razor.Run(razorId, sw, null, model);
  1. 将sw字符串保存生成类.cs文件(根据参数配置生成文件名)

  2. 另外生成一个__重新生成.bat,__razor.cshtml.txt,方便后续用户重新生成实体类。

FreeSql.Tools

这是 FreeSql 衍生出来的辅助工具包,内含生成器等功能;作者:mypeng1985 因为这个不兼容mac,linux,所以作者建议使用dotnet-tool 命令行工具生成实体类,从而支持MAC/Linux系统。对于不是使用FreeSql的开发者,也能使用此工具,你只需要修改对应的模板即可。

使用方式:不多介绍。

  • https://github.com/2881099/Freesql.tools

  • 分为WPF ,WinForm + DSkin 版本(套网页)

  • 看了下代码,底层生成代码逻辑也是用的RazorEngine .NET Framework 下的RazorEngine代码生成介绍

预览图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309135.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java IDEA断点调试

断点调试(debug) 断点调试应用案例 01&#xff1a; package Assign;public class Debug01 {public static void main(String[] args) {int sum 0;for (int i 0;i<5;i){sumi;System.out.println(i);System.out.println(sum);}System.out.println("continue");} …

.NET Core请求控制器Action方法正确匹配,但为何404?

【导读】提前预祝各位端午节快乐。有时候我们会发现方法名称都正确匹配&#xff0c;但就是找不到对应请求接口&#xff0c;所以本文我们来深入了解下何时会出现接口请求404的情况。匹配控制器Action方法&#xff08;404&#xff09;首先我们创建一个web api应用程序&#xff0c…

布斯乘法以及带符号数的运算

乘法理解 对于最熟悉的十进制乘法很最基本的运算原理就是一个乘数乘以另一个乘数的个位、十位、百位数字然后求和。比如 放到二进制来看其实它也是这样的&#xff0c;多位数的乘法就是一个乘数乘上另一个乘数的各位求和。那么&#xff1a; 布斯算法及原理 原理 已经知道两…

angular 接入 IdentityServer4

angular 接入 IdentityServer4Intro最近把活动室预约的项目做了一个升级&#xff0c;预约活动室需要登录才能预约&#xff0c;并用 IdentityServer4 做了一个统一的登录注册中心&#xff0c;这样以后就可以把其他的需要用户操作的应用统一到 IdentityServer 这里&#xff0c;这…

主机Redis服务迁移到现有Docker Overlay网络

“《麻雀虽小&#xff0c;五脏俱全》之主机现有Redis服务迁移到Docker Swarm Overlay网络&#xff0c;并搭建高可用容器集群。hello, 好久不见&#xff0c;之前文章记录了一个实战的2C分布式项目的改造过程&#xff0c;结果如下&#xff1a;其中Redis并未完成容器化改造&#x…

Java控制结构

控制结构 程序流程控制介绍 顺序控制 分支控制if-else 单分支 案例演示 01: import java.util.Scanner; public class IfWorkDemo {public static void main(String[] args){Scanner myScanner new Scanner(System.in);System.out.println("input your age");int…

.Net Core Configuration源码探究

前言上篇文章我们演示了为Configuration添加Etcd数据源&#xff0c;并且了解到为Configuration扩展自定义数据源还是非常简单的&#xff0c;核心就是把数据源的数据按照一定的规则读取到指定的字典里&#xff0c;这些都得益于微软设计的合理性和便捷性。本篇文章我们将一起探究…

面试官:你说你喜欢研究新技术,那么请说说你对 Blazor 的了解

阅读本文大概需要 1.5 分钟。最近在几个微信 .NET 交流群里大家讨论比较频繁的话题就是这几天自己的面试经历。面试官&#xff1a;“你刚说你喜欢研究新技术&#xff0c;那么你对 Blazor 了解多少&#xff1f;”作为一位专注于 .NET 开发的软件工程师&#xff0c;你好意思说你对…

Java变量

变量 ​ 变量是程序的基本组成单位 变量的介绍 概念 变量相当于内存中一个数据存储空间的表示&#xff0c;你可以把变量看做是一个房间的门牌号&#xff0c;通过门牌号我们可以找到房间&#xff0c;而通过变量名可以访问到变量(值)。 01&#xff1a; class Test {public s…

[Student.Achieve] 学生教务管理系统开源

&#xff08;源自&#xff1a;https://neters.club&#xff09;一觉醒来Github改版了&#xff0c;我个人还是挺喜欢的????。还有两个月就是老张做开源两周年了&#xff0c;时间真快&#xff0c;也慢慢的贡献了很多的开源作品&#xff0c;上边的是主要的七个作品&#xff0c…

.NET Core HttpClient源码探究

前言在之前的文章我们介绍过HttpClient相关的服务发现&#xff0c;确实HttpClient是目前.NET Core进行Http网络编程的的主要手段。在之前的介绍中也看到了&#xff0c;我们使用了一个很重要的抽象HttpMessageHandler&#xff0c;接下来我们就探究一下HttpClient源码&#xff0c…

Java 多线程:线程优先级

1 优先级取值范围 Java 线程优先级使用 1 ~ 10 的整数表示&#xff1a; 最低优先级 1&#xff1a;Thread.MIN_PRIORITY 最高优先级 10&#xff1a;Thread.MAX_PRIORITY 普通优先级 5&#xff1a;Thread.NORM_PRIORITY 2 获取线程优先级 public static void main(String[]…

《Unit Testing》1.1 -1.2 单元测试的目的

本系列是《Unit Testing》 一书的读书笔记 精华提取。书中的例子 C# 语言编写&#xff0c;但概念是通用的&#xff0c;只要懂得面向对象编程就可以。 单元测试当前的状态目前&#xff0c;在&#xff08;美国的&#xff09;大部分公司里&#xff0c;单元测试都是强制性的。生产…

Java Exception

Exception 异常捕获 将代码块选中->ctrlaltt->选中try-catch 01: public class Exception01 {public static void main(String[] args) {int n1 10;int n2 0;try {int res n1/n2;} catch (Exception e) { // e.printStackTrace();System.out.println(e.…

《Unit Testing》1.3 使用覆盖率指标来度量测试套件的好坏

使用覆盖率来度量测试套件&#xff08;Test Suite&#xff09;的质量有两种比较流行的测试覆盖率的度量方法&#xff1a;代码覆盖率分支覆盖率覆盖率度量会显示一个测试套件&#xff08;Test Suite&#xff09;会执行多少代码&#xff0c;范围从 0 至 100%。除了上述两种方法之…

Linux创始人:v5.8是有史以来最大的发行版之一

导语Linux v5.8已经修改了所有文件的20&#xff05;&#xff0c;是迄今为止变化最大的一次发行版。正文Linux创始人Linus Torvalds表示&#xff1a;Linux内核5.8版是“我们有史以来最大的发行版之一”。如果一切顺利&#xff0c;Linux v5.8稳定版应该在2020年8月的某个时候出现…

[高等数学]这你不背?

求导及求微分的基本公式: 泰勒中值定理: 麦克劳林公式: 不定积分公式: 凑微分: 第二类换元积分法常用的三种情况: 求高阶导数的几个公式: 二阶常系数非齐次线性微分方程的特解: 排列组合公式: C的计算&#xff1a; 下标的数字乘以上标的数字的个数,且每个数字都要-1.再除以上标…

怎么开会才不浪费时间?

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「148」篇原创敬上大家好&#xff0c;我是Z哥&#xff0c;先祝大家端午节日快乐。节日期间就发篇比较短的文章吧。人在职场混&#xff0c;开会应该是本职工作之外花…

.NET 5.0预览版6发布:支持Windows ARM64设备

2020年6月25日&#xff0c;微软dotnet团队在博客宣布了第六个 .NET 5.0 的预览版&#xff1a;https://devblogs.microsoft.com/dotnet/announcing-net-5-0-preview-6/&#xff0c;在改进性能的同时增加了一些新的功能。ASP.NET Core和 EF Core也将于今日发布了。注意&#xff1…