FreeSql 開源發佈快一年了,立志成爲 .Net 平臺方便好用的 ORM,倉庫地址:https://github.com/2881099/FreeSqlhtml
隨着不斷的迭代更新,愈來愈穩定,也愈來愈強大。預計在一週年的時候(2020年1月1日)發佈 1.0 正式版本。git
金九銀十的日子過去了,在這個銅通常的月份裏,鄙人作了幾個重大功能,但願對使用者開發提供更大的便利。github
如下的代碼,先決定義代碼以下 :sql
IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\db1.db;Max Pool Size=10";) .UseAutoSyncStructure(true) //自動同步實體結構到數據庫 .Build(); public class Blog { public Guid Id { get; set; } public string Url { get; set; } public int Rating { get; set; } }
class Dto { public Guid Id { get; set; } public string Url { get; set; } public int xxx { get; set; } } fsql.Select<Blog>().ToList<Dto>(); //SELECT Id, Url FROM Blog fsql.Select<Blog>().ToList(a => new Dto { xxx = a.Rating} ); //SELECT Id, Url, Rating as xxx FROM Blog //這樣寫,附加全部映射,再額外映射 xxx fsql.Select<Blog>().ToList(a => new Blog { Id = a.Id }) //這樣寫,只查詢 id fsql.Select<Blog>().ToList(a => new { a.Id }) //這樣寫,只查詢 id,返回匿名對象
映射支持單表/多表,是在查詢數據以前映射(不是先查詢全部字段再到內存映射)數據庫
查找規則,查找屬性名,會循環內部對象 _tables(join 查詢後會增加),以 主表優先查,直到查到相同的字段。數組
如:ide
A, B, C 都有 id,Dto { id, a1, a2, b1, b2 },A.id 被映射。也能夠指定 id = C.id 映射。性能
友情提醒:在 dto 能夠直接映射一個導航屬性單元測試
以前已經實現,有設置關係,和未設置關係 的導航集合屬性聯級加載。測試
有設置關係的(支持一對多、多對多):
fsql.Select<Tag>().IncludeMany(a => a.Goods).ToList();
未設置關係的,臨時指定關係(只支持一對多):
fsql.Select<Goods>().IncludeMany(a => a.Comment.Where(b => b.TagId == a.Id));
只查詢每項子集合的前幾條數據,避免像EfCore加載全部數據致使IO性能低下(好比某商品下有2000條評論):
fsql.Select<Goods>().IncludeMany(a => a.Comment.Take(10));
上面已有的 IncludeMany 功能還不夠自由靈活。
老的 IncludeMany 限制只能在 ISelect 內使用,必需要先查上級數據,解決這個問題咱們作了直接在 Dto 上作映射:
查詢 Goods 商品表,分類一、分類二、分類3 各10條數據
//定義臨時類,也能夠是 Dto 類 class Dto { public int TypeId { get; set; } public List<Goods > GoodsList { get; set; } } var dto = new [] { 1,2,3 }.Select(a => new Dto { TypeId = a }).ToList(); dto.IncludeMany(d => d.GoodsList.Take(10).Where(gd => gd.TypeId == d.TypeId)); //執行後,dto 每一個元素.Vods 將只有 10條記錄
如今 IncludeMany 再也不是 ISelect 的專利,普通的 List<T> 也能夠用它來貪婪加載數據,並準確填充到內部各元素中。
老的 IncludeMany 限制只能查子表的全部字段,子表過段多過的話比較浪費 IO 性能。
新功能能夠設置子集合返回部分字段,避免子集合字段過多的問題。
fsql.Select<Tag>().IncludeMany(a => a.Goods.Select(b => new Goods { Id = b.Id, Title = b.Title })); //只查詢 goods 表 id, title 字段,再做填充
相信不少 ORM 解析表達式的時候處理不了這個問題,咱們以前已經解決了 99%。
這個月發現還有一餘孽未清,發現問題後及時解決了,並增長單元測試代碼以絕後患。
在此以前,FreeSql.DbContext 和 倉儲實現,已經實現了聯級保存功能,以下:
聯級保存功能可實現保存對象的時候,將其【OneToMany】、【ManyToMany】導航屬性集合也一併保存。
全局關閉:
fsql.SetDbContextOptions(opt => opt.EnableAddOrUpdateNavigateList = false);
局部關閉:
var repo = fsql.GetRepository<T>(); repo.DbContextOptions.EnableAddOrUpdateNavigateList = false;
保存實體的指定【多對多】導航屬性,SaveManyToMany 方法實如今 BaseRepository、DbContext。
解決問題:當實體類導航數據過於複雜的時候,選擇關閉聯級保存的功能是明智之選,可是此時【多對多】數據保存功能寫起來很是繁瑣麻煩(由於要與現有數據對比後保存)。
var song = new Song { Id = 1 }; song.Tags = new List<Tag>(); song.Tags.Add(new Tag ...); song.Tags.Add(new Tag ...); song.Tags.Add(new Tag ...); repo.SaveManyToMany(song, "Tags"); //輕鬆保存 song 與 tag 表的關聯
機制規則與聯級保存的【多對多】同樣,以下:
咱們對中間表的保存是完整對比操做,對外部實體的操做只做新增(注意不會更新)
fsql.CodeFirst.SyncStructure(typeof(Log), "Log_1"); //遷移到 Log_1 表 fsql.CodeFirst.SyncStructure(typeof(Log), "Log_2"); //遷移到 Log_2 表
在此功能上,咱們對分表功能作了點升級,如下動做都會作遷移動做:
fsql.Select<Log>().AsTable((_, oldname) => $"{oldname}_1"); fsql.GetRepository<Log>(null, oldname => $"{oldname}_1");
FreeSql 提供了多種插入或更新方法,v0.11 以前主要使用 FreeSql.Repository/FreeSql.DbContext 庫提供的方法實現。
FreeSql.Repository 之 InsertOrUpdate
此方法與 FreeSql.DbContext AddOrUpdate 方法功能同樣。
var repo = fsql.GetRepository<T>(); repo.InsertOrUpdate(實體);
若是內部的狀態管理存在數據,則更新。
若是內部的狀態管理不存在數據,同查詢數據庫,是否存在。
存在則更新,不存在則插入
缺點:不支持批量操做
FreeSql.Provider.MySql 和 FreeSql.Provider.MySqlConnector 在 v0.11.11 版本已支持 MySql 特有的功能,On Duplicate Key Update。
這個功能也能夠實現插入或更新數據,而且支持批量操做。
class TestOnDuplicateKeyUpdateInfo { [Column(IsIdentity = true)] public int id { get; set; } public string title { get; set; } public DateTime time { get; set; } } var item = new TestOnDuplicateKeyUpdateInfo { id = 100, title = "title-100", time = DateTime.Parse("2000-01-01") }; fsql.Insert(item) .NoneParameter() .OnDuplicateKeyUpdate().ToSql(); //INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`, `time`) VALUES(100, 'title-100', '2000-01-01 00:00:00.000') //ON DUPLICATE KEY UPDATE //`title` = VALUES(`title`), //`time` = VALUES(`time`)
OnDuplicateKeyUpdate() 以後能夠調用的方法:
方法名 | 描述 |
---|---|
IgnoreColumns | 忽略更新的列,機制和 IUpdate.IgnoreColumns 同樣 |
UpdateColumns | 指定更新的列,機制和 IUpdate.UpdateColumns 同樣 |
Set | 手工指定更新的列,與 IUpdate.Set 功能同樣 |
SetRaw | 做爲 Set 方法的補充,可傳入 SQL 字符串 |
ToSql | 返回即將執行的 SQL 語句 |
ExecuteAffrows | 執行,返回影響的行數 |
IInsert 與 OnDuplicateKeyUpdate 都有 IgnoreColumns、UpdateColumns 方法。
當插入實體/集合實體的時候,忽略了 time 列,代碼以下:
fsql.Insert(item) .IgnoreColumns(a => a.time) .NoneParameter() .OnDuplicateKeyUpdate().ToSql(); //INSERT INTO `TestOnDuplicateKeyUpdateInfo`(`id`, `title`) VALUES(200, 'title-200') //ON DUPLICATE KEY UPDATE //`title` = VALUES(`title`), //`time` = '2000-01-01 00:00:00.000'
咱們發現,UPDATE time 部分變成了常量,而不是 VALUES(`time`),機制以下:
當 insert 部分中存在的列,在 update 中將以 VALUES(`字段`) 的形式設置;
當 insert 部分中不存在的列,在 update 中將爲常量形式設置,當操做實體數組的時候,此常量爲 case when ... end 執行(與 IUpdate 同樣);
使用方法 MySql OnDuplicateKeyUpdate 大體相同。
默認 IDelete 不支持導航對象,多表關聯等。ISelect.ToDelete 可將查詢轉爲刪除對象,以便支持導航對象或其餘查詢功能刪除數據,以下:
fsql.Select<T1>().Where(a => a.Options.xxx == 1).ToDelete().ExecuteAffrows();
注意:此方法不是將數據查詢到內存循環刪除,上面的代碼產生以下 SQL 執行:
DELETE FROM `T1` WHERE id in (select a.id from T1 a left join Options b on b.t1id = a.id where b.xxx = 1)
複雜刪除使用該方案的好處:
還有 ISelect.ToUpdate 高級更新數據功能,使用方法相似
FreeSql 基礎層實現了 Select/Update/Delete 可設置的全局過濾器功能。
public static AsyncLocal<Guid> TenantId { get; set; } = new AsyncLocal<Guid>(); fsql.GlobalFilter .Apply<TestAddEnum>("test1", a => a.Id == TenantId.Value) .Apply<AuthorTest>("test2", a => a.Id == 111) .Apply<AuthorTest>("test3", a => a.Name == "11");
Apply 泛型參數能夠設置爲任何類型,當使用 Select/Update/Delete 方法時會進行過濾器匹配嘗試(try catch):
如何禁用?
fsql.Select<TestAddEnum>().ToList(); //全部生效 fsql.Select<TestAddEnum>().DisableGlobalFilter("test1").ToList(); //禁用 test1 fsql.Select<TestAddEnum>().DisableGlobalFilter().ToList(); //禁用全部
fsql.Update/Delete 方法效果同上。
注意:IFreeSql.GlobalFilter 與 倉儲過濾器 不是一個功能,能夠同時生效
感謝反饋 bug 的朋友!
倉庫地址:https://github.com/2881099/FreeSql
請移步更新日誌:https://github.com/2881099/FreeSql/wiki/%e6%9b%b4%e6%96%b0%e6%97%a5%e5%bf%97
原文出處:https://www.cnblogs.com/kellynic/p/11881941.html