[開源] 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+,生態也逐漸完善,有得到許多網友的鼓勵和支持,感謝你們!感謝參與項目的你們!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章