前言
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) | |
short, short? | smallint(6) | number(6) | |||
int, int? | int(11) | int | int4 | number(11) | integer |
long, long? | bigint(20) | bigint | int8 | number(21) | |
byte, byte? | tinyint(3) unsigned | tinyint | number(3) | ||
ushort, ushort? | smallint(5) unsigned | number(5) | unsigned | ||
uint, uint? | int(10) unsigned | 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) | |
float, float? | real | float4 | float(63) | ||
decimal, decimal? | decimal(10,2) | numeric(10,2) | number(10,2) | ||
Guid, Guid? | char(36) | uniqueidentifier | uuid | char(36 CHAR) | character(36) |
TimeSpan, TimeSpan? | time | interval day(2) to second(6) | |||
DateTime, DateTime? | datetime | timestamp | timestamp(6) | ||
DateTimeOffset DateTimeOffset? | - | datetimeoffset | timestamp(6) with local time zone | ||
Enum, Enum? | enum | number(16) | mediumint | ||
FlagsEnum, FlagsEnum? | set | number(32) | |||
byte[] | varbinary(255) | bytea | blob | ||
string | varchar(255) | nvarchar(255) | nvarchar2(255) | ||
MygisPoint | point | ||||
MygisLineString | linestring | ||||
MygisPolygon | polygon | ||||
MygisMultiPoint | multipoint | ||||
MygisMultiLineString | multilinestring | ||||
MygisMultiPolygon | multipolygon | ||||
BitArray | varbit(64) | ||||
NpgsqlPoint NpgsqlPoint? | |||||
NpgsqlLine NpgsqlLine? | line | ||||
NpgsqlLSeg NpgsqlLSeg? | lseg | ||||
NpgsqlBox NpgsqlBox? | box | ||||
NpgsqlPath NpgsqlPath? | path | ||||
NpgsqlPolygon NpgsqlPolygon? | |||||
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 | |||||
PostgisPolygon | |||||
PostgisMultiPoint | |||||
PostgisMultiLineString | |||||
PostgisMultiPolygon | |||||
PostgisGeometry | |||||
PostgisGeometryCollection | |||||
Dictionary<string, string> | hstore | ||||
JToken | jsonb | ||||
JObject | |||||
JArray | |||||
數組 | 以上所有類型都支援 |
以上類型和長度是預設值,可手工設定,如 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.zip、Demo for dotnet 2.2.zip
第一步:
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(已滿)、8578575(線上)、52508226(線上)
github: https://github.com/2881099/FreeSql
說好的抽獎呢???