[开源] FreeSql 配套工具,基于 Razor 模板实现最高兼容的生成器

FreeSql 经过半年的开发和坚持维护,在 0.6.x 版本中完成了几大重要事件:

1、按小包拆分,每个数据库实现为单独 dll;

2、实现 .net framework 4.5 支持;

3、同时支持 MySql.Data、MySqlConnector 的实现;

4、自定义导航属性关系的配置;

5、配套工具 FreeSql.Tools 发布;

本文主要讲解第5项《FreeSql.Tools》,大主角往往在最后才出现!!!

1|0拆分小包

在此之前一直被吐槽 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

2|0支持 .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

3|0MySqlConnector 的实现

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; }

4|0自定义导航属性关系的配置

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; }

然后就能使用很多导航的骚操作功能了。

5|0配套工具 FreeSql.Tools 发布(主角压轴)

在此感谢这个工具的作者:mypeng1985,和参考者:movingsam

感谢有你们一帮热心的使用者,帮助 FreeSql 生态添砖加瓦!!

FreeSql 在早期做过一套生成器模板,功能比较隐秘,一般人不知道如何使用。。之后就一直沉迷于 CodeFirst 的功能开发,无法自拔。

然后在10天前,突然感觉 FreeSql 多了好多使用者,这个时间当然需要有从数据库生成实体的需求了!!

Q:没必要搞这种东西了吧 市面上蛮多的,或者搞一套模板完全搞定了?

A:

  • 无法100%类型兼容啊,因为 FreeSql 支持的类型真的很深,然后市场上的类型映射做不到 100% 匹配;

  • 为了挖掘更多功能,生成器还需要有导航属性的支持,这是基本的,因为有导航属性后,FreeSql 操作会骚许多;

本来我发起了一个纯 winform 的生成器项目,界面都做好了如下:

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

直接被秒杀了,这是来自作者:mypeng1985 的佳作。

界面看上去非常像 web,但其实不是的,仍然是一个 winform 程序,使用了 html 做界面,c# 做操作功能。

6|0结束语

源码地址:https://github.com/2881099/FreeSql.Tools

FreeSql 从 2018年11月28日立项,开发,到今天 0.6.x,单元测试 1600+,生态也逐渐完善,有得到许多网友的鼓励和支持,感谢你们!感谢参与项目的你们!


__EOF__

本文作者FreeSql & CSRedis
本文链接https://www.cnblogs.com/kellynic/p/10975658.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   nicye  阅读(2185)  评论(11编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示