FreeSql 新的八大騷功能,.NETCore 你必須曉得的 ORM

前言

FreeSql 目前版本號 0.5.5,預計明年元旦發佈 1.0.0,切莫小看了版本號,目前單元測試方法1350+,並且每個方法內的涵蓋面又比較廣(不信的話見下圖),每一次版本發佈都作了較多的測試工作。

最近的一段時間,關注我們的人時不時會看見擴展包發佈,今天振奮人心的功能主要是核心部分實現(擴展包今天當配角)。就不多囉嗦了,咱們直接入主題。

功能一:MapType 類型映射

使用 codefirst 時序列化 json 或 jsonb 數據類型報錯

使用 postgresql + ef 配置數據映射關係,使用 FreeSql 的映射擴展時,對於json類型的數據映射出錯。

這是來自 github 上的某個 issue,原因是用戶的實體定義了 string,數據庫類型爲 json。FreeSql 本身支持了豐富的類型,不限於 json,但是限定了類型的映射,比如 JToken/JObject/JArray 的實體類型纔可以映射至 PostgreSQL 數據庫的 json 類型。另外雖然有 DbType 特性可以設置,但使用範圍有限,不可跨越類型(如使用 string 可使用 DbType="char(100)")。

還有類似的,如:將 enum 映射到數據庫 varchar 的請求。。。。

到現在,我們已經徹底突破了這個障礙,基本可以做到隨意映射類型。作爲新項目開發,我們提供本身的默認類型映射已經非常人性化,提這些需求的人主要還是歷史原因,咱們做程序維護工作的人員還是佔比很高,千怪萬怪只能怪 FreeSql 來得太遲。。。。

目前爲 MapType 功能增加了大約 400 個單元測試方法。貼一段 demo 配置方法:

class EnumTestMap {
    public Guid id { get; set; }

    [Column(MapType = typeof(string))]
    public ToStringMapEnum enum_to_string { get; set; }
    [Column(MapType = typeof(string))]
    public ToStringMapEnum? enumnullable_to_string { get; set; }

    [Column(MapType = typeof(int))]
    public ToStringMapEnum enum_to_int { get; set; }
    [Column(MapType = typeof(int?))]
    public ToStringMapEnum? enumnullable_to_int { get; set; }

    [Column(MapType = typeof(string))]
    public BigInteger biginteger_to_string { get; set; }
    [Column(MapType = typeof(string))]
    public BigInteger? bigintegernullable_to_string { get; set; }
}
public enum ToStringMapEnum { 中國人, abc, 香港 }

應該不需要解釋了吧?

細看一下,實體內有 BigInteger 類型,這可是數據庫無法表示的類型,現在就是可以使用(沒轍)。但請注意:BigInteger 僅僅是 CURD 方便, Equals == 判斷可以使用,無法使用 + - * / < > 等操作;

默認映射

csharp MySql SqlServer PostgreSQL Oracle Sqlite
bool, bool? bit(1) bit bool number(1) boolean
sbyte, sbyte? tinyint(3) smallint int2 number(4) smallint
short, short? smallint(6) smallint int2 number(6) smallint
int, int? int(11) int int4 number(11) integer
long, long? bigint(20) bigint int8 number(21) integer
byte, byte? tinyint(3) unsigned tinyint int2 number(3) int2
ushort, ushort? smallint(5) unsigned int int4 number(5) unsigned
uint, uint? int(10) unsigned bigint int8 number(10) decimal(10,0)
ulong, ulong? bigint(20) unsigned decimal(20,0) numeric(20,0) number(20) decimal(21,0)
double, double? double float float8 float(126) double
float, float? float real float4 float(63) float
decimal, decimal? decimal(10,2) decimal(10,2) numeric(10,2) number(10,2) decimal(10,2)
Guid, Guid? char(36) uniqueidentifier uuid char(36 CHAR) character(36)
TimeSpan, TimeSpan? time time time interval day(2) to second(6) bigint
DateTime, DateTime? datetime datetime timestamp timestamp(6) datetime
DateTimeOffset
DateTimeOffset?
- - datetimeoffset timestamp(6) with local time zone -
Enum, Enum? enum int int4 number(16) mediumint
FlagsEnum, FlagsEnum? set bigint int8 number(32) bigint
byte[] varbinary(255) varbinary(255) bytea blob blob
string varchar(255) nvarchar(255) varchar(255) nvarchar2(255) nvarchar(255)
MygisPoint point - - - -
MygisLineString linestring - - - -
MygisPolygon polygon - - - -
MygisMultiPoint multipoint - - - -
MygisMultiLineString multilinestring - - - -
MygisMultiPolygon multipolygon - - - -
BitArray - - varbit(64) - -
NpgsqlPoint
NpgsqlPoint?
- - point - -
NpgsqlLine
NpgsqlLine?
- - line - -
NpgsqlLSeg
NpgsqlLSeg?
- - lseg - -
NpgsqlBox
NpgsqlBox?
- - box - -
NpgsqlPath
NpgsqlPath?
- - path - -
NpgsqlPolygon
NpgsqlPolygon?
- - polygon - -
NpgsqlCircle
NpgsqlCircle?
- - circle - -
(IPAddress, int)
(IPAddress, int)?
- - cidr - -
IPAddress - - inet - -
PhysicalAddress - - macaddr - -
NpgsqlRange<int>
NpgsqlRange<int>?
- - int4range - -
NpgsqlRange<long>
NpgsqlRange<long>?
- - int8range - -
NpgsqlRange<decimal>
NpgsqlRange<decimal>?
- - numrange - -
NpgsqlRange<DateTime>
NpgsqlRange<DateTime>?
- - tsrange - -
PostgisPoint - - geometry - -
PostgisLineString - - geometry - -
PostgisPolygon - - geometry - -
PostgisMultiPoint - - geometry - -
PostgisMultiLineString - - geometry - -
PostgisMultiPolygon - - geometry - -
PostgisGeometry - - geometry - -
PostgisGeometryCollection - - geometry - -
Dictionary<string, string> - - hstore - -
JToken - - jsonb - -
JObject - - jsonb - -
JArray - - jsonb - -
數組 - - 以上所有類型都支持 - -

以上類型和長度是默認值,可手工設置,如 string 屬性可指定 [Column(DbType = "varchar(max)")]

功能二:唯一鍵(Unique)

class AddUniquesInfo {

    public Guid id { get; set; }
    [Column(Unique = "uk_phone")]
    public string phone { get; set; }

    [Column(Unique = "uk_group_index")]
    public string group { get; set; }
    [Column(Unique = "uk_group_index")]
    public int index { get; set; }

    [Column(Unique = "uk_group_index222")]
    public string index22 { get; set; }
}

Unique 指定相同的標識,代表聯合唯一鍵,現已支持遷移。

功能三:弱類型(實體)

之前在操作實體時,必須傳統泛型參數,現在可以實現弱類型實體的操作。以 Repository 爲例:

var repos = fsql.GetGuidRepository<object>();
repos.AsType(typeof(AddUpdateInfo));

var item = new AddUpdateInfo();
repos.Insert(item);

item.Clicks += 1;
repos.InsertOrUpdate(item);

var item2 = repos.Find(item.Id) as AddUpdateInfo;
Assert.Equal(item.Clicks, item2.Clicks);

repos.DataFilter.Apply("xxx", a => (a as AddUpdateInfo).Clicks == 11);
Assert.Null(repos.Find(item.Id));

然後呢,DbContext 也支持同樣的操作。

dotnet add package FreeSql.DbContext

功能四:ToList & Mapper

現在支持 ToList(a => new Dto()) 這樣的簡單數據映射。

什麼意思?即 Dto 只要有屬性名與實體屬性相同,就會根據匹配到的字段查詢(不是查詢所有字段回來再映射)。

然後這個騷操作,還支持多表查詢的映射,怎麼解決多表存在相同名字的字段問題呢?優先級規則,它會依次序匹配 LeftJoin/InnerJoin/RightJoin 的實體。

功能五:ToList 貪婪加載

以前 .ToList() 會加載兩級Join對象;

現在 ISelect.ToList(includeNestedMembers: true) 貪婪加載所有 LeftJoin/InnerJoin/RightJoin 導航數據,不論對象的層級;

功能六:WhereDynamic 動態條件

支持傳入動態對象如:主鍵值 | new[]{主鍵值1,主鍵值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}。

也就是說 WhereDynaimc 方法輸入類型爲 object,是不是很方便?還支持聯合主鍵呢。

功能七:IAdo.Query 多個結果集

var result = fsql.Ado.Query<T1, T2>("select * from t1; select * from t2");

功能八:開發環境之利器:MVC 中間件 FreeSql.AdminLTE

大約是前一段時間的某一天(廢話),因爲使用 FreeSql 的某項目需要做一個簡單的後臺功能,以便錄入或管理數據。在實施的過程中好懷念當初 dotnetGen 生成器的味道,用它產生 curd 基本功能幾乎是秒做;

FreeSql.AdminLTE,是的就是它,前段時間發佈過一次。

它是 FreeSql 衍生出來的 .NETCore MVC 中間件、中間件、中間件(重複三遍)擴展包,基於 AdminLTE 前端框架動態產生實體的增刪查改界面;

輸入:實體1、實體2、實體3

輸出:後臺管理的功能

只需要傳入實體,就可以形成 curd 的管理功能,是不是有些騷啊~~~

先發一張運行後的圖片嚐個鮮:

這是根據實體產生 curd 界面的 mvc 中間件,開發時預覽數據好方便啊。看完預覽圖不由得再感嘆一次 FreeSql 的易用性,那句口號:做 .NETCore 最方便的 ORM! 沒有說錯。。。作者多次提及:“我們是日式簡約風格,沒那麼複雜的用法”,也驗證了這一點。。

添加/修改

中件間產生的界面包括添加、修改數據的功能,普通實體的根據屬性的類型與 Html5 UI 一一映射;

比較特殊的映射規則:

c# 類型 Html5
布爾 複選框
枚舉 下拉選擇
日期 日期控件
ManyToOne 導航屬性 下拉選擇
ManyToMany 導航屬性 多選器

等等。。。

什麼情況會產生【上傳文件】控件?
有興趣的可以瞭解源碼,目前沒有開放在外部配置。

查詢/過濾

中件間爲每個實體提供了分頁列表查詢,每頁爲20條數據;

除此外,還提供了過濾條件的支持,規則是根據導航屬性(ManyToOne、ManyToMany)。比如【文章實體】,內含有【分類id】+【分類對象】,則【文章】列表頁會出現按【分類】篩選的UI,詳見上面的 demo 示意圖,或者下載對應的 demo 版本運行;

刪除

中件間爲每個實體提供了批量刪除的功能;

測試 demo

我們習慣用 sqlite 做測試庫,測試完畢直接刪除目錄,不留垃圾數據,所以下面的 demo 不需要修改任何地方,運行時自動建庫、建表;

提供 .net core 2.1、2.2 兩種環境的測試 demo 下載:

Demo for dotnet 2.1.zipDemo for dotnet 2.2.zip

image

第一步:

dotnet restore

第二步:

dotnet run

思考

一番驚喜過後,你應該會考慮實用性,這樣做有什麼價值,可用於什麼樣的場景?

這個擴展包簡單的輸入,產生巨量的功能反饋。目前來說它是死板的,對外提供的擴展性幾乎爲零,這樣也就限定了它的應用場景。

不合適的場景

1、它不可替代我們自身開發的後臺管理系統;

2、它不適合擺放在公網正式環境,存在數據安全問題;

3、歡迎補充。。。;

談談定位

目前的定位是這樣的,在開發環境中使用,查閱預覽實體數據,同時也比較方便的管理測試數據。

一段擁有無比力量的小段代碼,也是中間件界面的功能開啓:

//可以配置子目錄訪問,如:/testadmin/
app.UseFreeAdminLTE("/",
    typeof(Entities.Song),
    typeof(Entities.Tag));

觀後抽獎

我們一直在發佈純技術乾貨的分享文章,FreeSql 已經基本完成 .NETCore 最方便的 ORM 使命,我們正在籌備生態的建立,比如 ABP 中如何使用 FreeSql 的實現,需要各種各樣的擴展包,好多好多工作量。有沒有大神願意無償參與做這件事情,好吧。。應該沒有人!!如果你回心轉意了,歡迎聯繫我們。

歡迎持續關注我們,做 .NETCore 最方便的 ORM !

(QQ羣:4336577)

github: https://github.com/2881099/FreeSql

說好的抽獎呢???

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