[开源] FreeSql 配套工具,基于 Razor 模板实现最高兼容的生成器
FreeSql 经过半年的开发和坚持维护,在 0.6.x 版本中完成了几大重要事件:
1、按小包拆分,每个数据库实现为单独 dll;
2、实现 .net framework 4.5 支持;
3、同时支持 MySql.Data、MySqlConnector 的实现;
4、自定义导航属性关系的配置;
5、配套工具 FreeSql.Tools 发布;
本文主要讲解第5项《FreeSql.Tools》,大主角往往在最后才出现!!!
拆分小包
在此之前一直被吐槽 FreeSql 臃肿,没有小包开发理念。其实我是一点也不承认这种评价,虽然刚开始只有一个 FreeSql.dll,但是在开发和规划上简单了很多。
有一条开发原则这样讲道:过早优化是恶梦!
大概意思是无论做什么项目,不要想着一开始就过度系统的、规范的执行。从外界来看是正规了,但是进度和稳定性会大大折扣。可以不信我,但是请一定要相信前人的总结啊!!!
从之前的一个 dll 到拆分成小包,我们总共耗时两天,虽然都在一个项目内开发,但其实耦合性并不高,so easy!!
车到山前必有路,时机到了自然会拆。这个时机也是奠定 FreeSql 走出了稳定关键的一步。这样会有更多人愿意加入 FreeSql 阵营。
- 各数据库单独包、延时加载包;
- FreeSql.Extensions.LazyLoading
- FreeSql.Provider.MySql
- FreeSql.Provider.PostgreSQL
- FreeSql.Provider.SqlServer
- FreeSql.Provider.Sqlite
- FreeSql.Provider.Oracle
支持 .netframework 4.5
早期 FreeSql 主要是在 .net core 最方便的 ORM!NETStandard 是新的标准,然而前段时间微软又说 ..net5 将合并。。。变化真的太快。
在实现拆分小包后,其实 FreeSql 的模块更加清淅,并且依赖项非常之少,然后比较容易的做出了 4.5 framework 的适配。
目前支持的版本:
| Package Name | Version |
|---|---|
| FreeSql.Provider.MySql | NETStandard2.0、net452 |
| FreeSql.Provider.PostgreSQL | NETStandard2.0、net45 |
| FreeSql.Provider.SqlServer | NETStandard2.0、net451 |
| FreeSql.Provider.Sqlite | NETStandard2.0、net45 |
| FreeSql.Provider.Oracle | NETStandard2.0、net45 |
| FreeSql.Extensions.LazyLoading | NETStandard2.0、net45 |
MySqlConnector 的实现
mysql 是一个神奇的流行数据库,在 .net 阵营中使用量排名老二。mysql 的版本五花八门,从 5.6 开始有了不同的分支,分支的出现使得 ado.net 驱动不通用。
很多人不推荐使用 MySql.Data 官方驱动,但是 FreeSql 一直在使用官驱,并且支持了所有 5.6 类型,包括 enum/set 等。
然后就有一些人,特别是高手的那些来提出要求,适配一个 MySqlConnector 的实现,然后著名的 A大(茶叔)提了一道 PR ,创建了 FreeSql.Provider.MySqlConnector 项目,99.9999% 源码和原来 FreeSql.Provider.MySql 相同,经过 266 个单元测试后发现,只需要兼容 enum/set 类型,参数化 ? @ 的处理就跑通了。然后就有了现在新的驱动包:
| Package Name | Version |
|---|---|
| FreeSql.Provider.MySqlConnector | NETStandard2.0、net45 |
然后 FreeSqlBuilder 使用反射决定使用哪个 mysql 驱动。代码如下:
public IFreeSql<TMark> Build<TMark>() {
if (string.IsNullOrEmpty(_masterConnectionString)) throw new Exception("参数 masterConnectionString 不可为空,请检查 UseConnectionString");
IFreeSql<TMark> ret = null;
Type type = null;
switch(_dataType) {
case DataType.MySql:
type = Type.GetType("FreeSql.MySql.MySqlProvider`1,FreeSql.Provider.MySql")?.MakeGenericType(typeof(TMark));
if (type == null) type = Type.GetType("FreeSql.MySql.MySqlProvider`1,FreeSql.Provider.MySqlConnector")?.MakeGenericType(typeof(TMark));
if (type == null) throw new Exception("缺少 FreeSql 数据库实现包:FreeSql.Provider.MySql.dll,可前往 nuget 下载");
break;
case DataType.SqlServer: type = Type.GetType("FreeSql.SqlServer.SqlServerProvider`1,FreeSql.Provider.SqlServer")?.MakeGenericType(typeof(TMark));
if (type == null) throw new Exception("缺少 FreeSql 数据库实现包:FreeSql.Provider.SqlServer.dll,可前往 nuget 下载");
break;
case DataType.PostgreSQL: type = Type.GetType("FreeSql.PostgreSQL.PostgreSQLProvider`1,FreeSql.Provider.PostgreSQL")?.MakeGenericType(typeof(TMark));
if (type == null) throw new Exception("缺少 FreeSql 数据库实现包:FreeSql.Provider.PostgreSQL.dll,可前往 nuget 下载");
break;
case DataType.Oracle: type = Type.GetType("FreeSql.Oracle.OracleProvider`1,FreeSql.Provider.Oracle")?.MakeGenericType(typeof(TMark));
if (type == null) throw new Exception("缺少 FreeSql 数据库实现包:FreeSql.Provider.Oracle.dll,可前往 nuget 下载");
break;
case DataType.Sqlite: type = Type.GetType("FreeSql.Sqlite.SqliteProvider`1,FreeSql.Provider.Sqlite")?.MakeGenericType(typeof(TMark));
if (type == null) throw new Exception("缺少 FreeSql 数据库实现包:FreeSql.Provider.Sqlite.dll,可前往 nuget 下载");
break;
default: throw new Exception("未指定 UseConnectionString");
}
ret = Activator.CreateInstance(type, new object[] { _masterConnectionString, _slaveConnectionString }) as IFreeSql<TMark>;
if (ret != null) {
ret.CodeFirst.IsAutoSyncStructure = _isAutoSyncStructure;
ret.CodeFirst.IsSyncStructureToLower = _isSyncStructureToLower;
ret.CodeFirst.IsSyncStructureToUpper = _isSyncStructureToUpper;
ret.CodeFirst.IsConfigEntityFromDbFirst = _isConfigEntityFromDbFirst;
ret.CodeFirst.IsNoneCommandParameter = _isNoneCommandParameter;
ret.CodeFirst.IsLazyLoading = _isLazyLoading;
var ado = ret.Ado as Internal.CommonProvider.AdoProvider;
ado.AopCommandExecuting += _aopCommandExecuting;
ado.AopCommandExecuted += _aopCommandExecuted;
}
return ret;
}
自定义导航属性关系的配置
FreeSql 原先支持约定式导航关系配置,对于新项目开发无疑可约定,但是很多老项目命名不规范的就使用不了相关的功能。
有关约定配置可参考 github wiki 中心文档
QQ 开发群真是个好平台,在发起讨论后,各位大佬都纷纷提出建议,最后以一票否决了各大建议,哈哈。。
主要从语法和用户使用的感受上设计,还是那个理念:日式简约!不能加入太多特性和功能,增加用户的理解和使用成本。
最终效果如下:
//导航属性,OneToMany
[Navigate("Song_id")]
public virtual List<song_tag> Obj_song_tag { get; set; }
//导航属性,ManyToOne/OneToOne
[Navigate("Song_id")]
public virtual song Obj_song { get; set; }
[Navigate("Tag_id")]
public virtual tag Obj_tag { get; set; }
然后就能使用很多导航的骚操作功能了。
配套工具 FreeSql.Tools 发布(主角压轴)
在此感谢这个工具的作者:mypeng1985,和参考者:movingsam
感谢有你们一帮热心的使用者,帮助 FreeSql 生态添砖加瓦!!
FreeSql 在早期做过一套生成器模板,功能比较隐秘,一般人不知道如何使用。。之后就一直沉迷于 CodeFirst 的功能开发,无法自拔。
然后在10天前,突然感觉 FreeSql 多了好多使用者,这个时间当然需要有从数据库生成实体的需求了!!
Q:没必要搞这种东西了吧 市面上蛮多的,或者搞一套模板完全搞定了?
A:
无法100%类型兼容啊,因为 FreeSql 支持的类型真的很深,然后市场上的类型映射做不到 100% 匹配;
为了挖掘更多功能,生成器还需要有导航属性的支持,这是基本的,因为有导航属性后,FreeSql 操作会骚许多;
本来我发起了一个纯 winform 的生成器项目,界面都做好了如下:

是不是觉得很好看?我觉得好看。。。。其他人觉得丑。我在开发群发给大家看了之后,第二天 FreeSql.Tools 项目就搞出了新的界面,如下:

直接被秒杀了,这是来自作者:mypeng1985 的佳作。
界面看上去非常像 web,但其实不是的,仍然是一个 winform 程序,使用了 html 做界面,c# 做操作功能。
结束语
源码地址:https://github.com/2881099/FreeSql.Tools
FreeSql 从 2018年11月28日立项,开发,到今天 0.6.x,单元测试 1600+,生态也逐渐完善,有得到许多网友的鼓励和支持,感谢你们!感谢参与项目的你们!
[开源] FreeSql 配套工具,基于 Razor 模板实现最高兼容的生成器的更多相关文章
- 基于ABP做一个简单的系统——实战篇:4.基于富文本编辑器,Razor模板引擎生成内容并导出Word 填坑记录
起因 需求是这样的,有一种协议需要生成,协议的模板是可配置的,在生成过程中,模板中的内容可以根据约定的标记进行替换(就像mvc的razor模板一样).生成后的内容还需要导出成word或pdf. 常见的 ...
- .NET Core/.NET5/.NET6 开源项目汇总13:模板引擎
系列目录 [已更新最新开发文章,点击查看详细] 开源项目是众多组织与个人分享的组件或项目,作者付出的心血我们是无法体会的,所以首先大家要心存感激.尊重.请严格遵守每个项目的开源协议后再使用.尊 ...
- 【Hades】ades是一个开源库,基于JPA和Spring构建,通过减少开发工作量显著的改进了数据访问层的实现
几乎每个应用系统都需要通过访问数据来完成工作.要想使用领域设计方法,你就需要为实体类定义和构建资源库来实现领域对象的持久化.目前开发人员经常使用JPA来实现持久化库.JPA让持久化变得非常容易,但是仍 ...
- Razor模板引擎
Razor模板引擎 阅读目录 一.简介 二.非Mvc中使用Razor 三.总结 回到目录 一.简介 在MVC以外的场景中,我们往往需要完成一些模板引擎生成代码或页面的工作:在以前我们一般常用的有Raz ...
- [转]MVC Razor模板引擎 @RenderBody、@RenderPage、@RenderSection及Html.RenderPartial、Html.RenderAction
本文参考自下面文章整理 MVC Razor模板引擎 @RenderBody.@RenderPage.@RenderSection及Html.RenderPartial.Html.RenderActio ...
- 脱离MVC使用Razor模板引擎
关于Razor模板引擎 1.简介 模板引擎:Razor.Nveocity.Vtemplate.Razor有VS自动提示.使用起来会方便一点. 但是Razor大多是在MVC下使用的. 那么如何在非MVC ...
- Razor模板引擎 (RazorEngine)
Razor模板引擎不仅在ASP.NET MVC中内置了Razor模板引擎,还有一个开源的RazorEngine, 这样以来我们可以在非ASP.NET MVC项目中使用Razor引擎,甚至在控制台,Wi ...
- Razor - 模板引擎 / 代码生成 - RazorEngine
目录 Brief Authors Official Website RazorEngine 的原理 - 官方解释 安装记录 Supported Syntax (默认实现支持的语法) 测试记录 - ca ...
- MVC的验证(模型注解和非侵入式脚本的结合使用) .Net中初探Redis .net通过代码发送邮件 Log4net (Log for .net) 使用GDI技术创建ASP.NET验证码 Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
MVC的验证(模型注解和非侵入式脚本的结合使用) @HtmlHrlper方式创建的标签,会自动生成一些属性,其中一些属性就是关于验证 如图示例: 模型注解 通过模型注解后,MVC的验证,包括前台客 ...
随机推荐
- Git介绍与简易搭建
Git介绍 Git(读音为/gɪt/.)是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发 ...
- 【Java基础】Annotation 的本质和自定义实现
Java 中注解的实现原理 一.引言 在 Java5 之前,利用 xml 进行配置是各大框架的常规操作,这种方式可以实现松耦合并完成框架中几乎所有需要的配置,但随着项目的扩展,xml 文件本身的内容将 ...
- Python语法速查: 7. 函数基础
返回目录 (1)函数基本 ● 函数是第一类对象 Python中万物皆对象,所有对象都是第一类的(first class),函数也不例外,也是第一类对象.既然是对象,那就可以当作普通的对象数据处理,比如 ...
- Java题库——Chapter11 继承和多态
1)Analyze the following code: public class Test { public static void main(String[ ] args) { B b = ne ...
- 发布方式一:发布.netcore流程
通过注册世纪互联,发布网站 注册需要上传身份证正反照片,以及打款一元,试用期一个月 https://www.azure.cn 注册完成后,进入主页面: 如图所示,创建完成后的效果: 点开详情, ...
- 资深程序员对于Python各个方向的面试经验分享,非常给力!
之前早有前辈们说过,"裸辞一时爽,一直裸辞一直爽",这话一点不假,裸辞你要面临没有收入来源,但是每天眼睁睁看着各种花销不断支出的煎熬,我主要是觉得一边在上家公司工作一边去下家面试可 ...
- Burpsuite抓取https数据包
Burpsuite抓取https包 浏览器代理设置 Burpsuite代理设置 启动Burpsuite,浏览器访问127.0.0.1:8080,点击CA Certificate,下载cacert.de ...
- apk系统签名小技巧
前言 对于经常和android系统打交道的攻城狮来说,给app打系统签名一定是日常操作啦.由于最近使用的比较多,特此总结一下,减少复制粘贴的操作,通过命令行来搞定. 简化前的操作 1.Android ...
- tomcat7控制台日志中文乱码
windows电脑 idea启动Tomcat调试程序时,Tomcat控制台输出里,中文是乱码. 解决办法: 修改Tomcat/bin/catalina.bat文件: set JAVA_OPTS= 的内 ...
- 流程控制之if,while,for
流程控制之if,while,for 一.if语法 就一个条件 age_of_girl = 18 if age_of_girl < 25: print("小姐姐") 两个条件 ...