FreeSql 新功能介紹:貪婪載入五種方法

nicye發表於2019-05-16

前言

FreeSql 在經過6個月的開發和朋友們的工作實踐,不斷的改進創新,目前擁有1500個左右單元測試方法,且每個方法內又覆蓋不同的測試面。

今天介紹 FreeSql 各種貪婪載入的姿勢,作下總結。本節內容對應的還有【延時載入】,貪婪載入和他本該在一起介紹,開發專案的過程中應該雙管齊下,才能寫出高質量的程式。有關延時載入,日後有空再單獨編寫。

FreeSql是一個功能強大的NETStandard庫,用於物件關係對映程式(O/RM),便於開發人員能夠使用 .NETStandard 物件來處理資料庫,不必經常編寫大部分資料訪問程式碼。

  • [√] 支援 CodeFirst 遷移;
  • [√] 支援 DbFirst 從資料庫匯入實體類,支援三種模板生成器;
  • [√] 採用 ExpressionTree 高效能讀取資料;
  • [√] 支援深入的型別對映,比如pgsql的陣列型別,堪稱匠心製作;
  • [√] 支援豐富的表示式函式;
  • [√] 支援導航屬性查詢,和延時載入;
  • [√] 支援同步/非同步資料庫操作方法,豐富多彩的鏈式查詢方法;
  • [√] 支援讀寫分離、分表分庫,租戶設計;
  • [√] 支援多種資料庫,MySql/SqlServer/PostgreSQL/Oracle/Sqlite;

貪婪方法一:Dto 對映查詢

Select<Tag>().Limit(10).ToList(a => new TestDto { id = a.Id, name = a.Title });
Select<Tag>().Limit(10).ToList(a => new TestDto());
Select<Tag>().Limit(10).ToList(a => new TestDto { });
Select<Tag>().Limit(10).ToList(a => new TestDto() { });
Select<Tag>().Limit(10).ToList<TestDto>();

像這種對映支援單表/多表。

查詢規則,查詢屬性名,會迴圈內部物件 _tables(join 查詢後會增長),以 主表優先查,直到查到相同的欄位。

如:

A, B, C 都有 id,Dto { id, a1, a2, b1, b2 },A.id 被對映。也可以指定 id = C.id 對映。

還可以在 dto 可以直接對映一個導航屬性。

對頭,通過對映某物件,也可以實現貪婪載入,這個功能是在資料庫查詢前對映的,而不是查回所有資料再重組。

貪婪方法二:導航屬性 ManyToOne/OneToOne

ManyToOne/OneToOne 導航屬性通過 ToList() 載入,這個方法有一個引數:includeNestedMembers。

引數說明:

false: 返回 2級 Join 的資料;

true: 返回所有層級深度 Join 的導航資料;

如果查詢中已經使用了 a.Parent.Parent 類似表示式,則可以無需 LeftJoin 等操作。

如:

class Tag {
    [Column(IsIdentity = true)]
    public int Id { get; set; }
    public string Name { get; set; }

    public int? Parent_id { get; set; }
    public virtual Tag Parent { get; set; }
}

Select<Tag>().Where(a => a.Parent.Name == "1").ToList();
//這樣寫,不需要再標記 Join,解析表示式時自動處理成 LeftJoin

如果導航屬性沒有使用,又想載入,可使用 Include 方法。(不好理解可跳過,也許只能在使用中體會)

Select<Tag>().Include(a => a.Parent).ToList();

貪婪方法三:導航屬性 ManyToMany

IncludeMany 貪婪載入集合的導航屬性,其實是分兩次查詢,在 ToList 後進行了資料重灌。

class Song {
    [Column(IsIdentity = true)]
    public int Id { get; set; }
    public string Title { get; set; }

    public virtual ICollection<Tag> Tags { get; set; }
}
class Song_tag {
    public int Song_id { get; set; }
    public virtual Song Song { get; set; }

    public int Tag_id { get; set; }
    public virtual Tag Tag { get; set; }
}

Select<Tag>().IncludeMany(a => a.Songs).ToList();
//這是 ManyToMany 關係的貪婪載入

IncludeMany 有第二個引數,可以進行第二次查詢前的修飾工作。

Select<Tag>().IncludeMany(a => a.Songs, 
    then => then.Where(song => song.User == "admin")).ToList();

然後,其實在 then 那裡,還可以繼續進行向下 Include/IncludeMany。只要你喜歡,向下 100 層都沒問題。

貪婪方法四:導航屬性 OneToMany

大體與 ManyToMany 用法相同,只是它沒有通過中間表查詢資料。

貪婪方法五:變異屬性 OneToMany

變異的 IncludeMany,即使選擇的不是導航屬性,也可以貪婪載入。適合一些些老專案,導航屬性配置不規則的,也可以一對多貪婪載入。

為了方便理解,我建立了下面兩個類,他們沒有配置導航關係。你可能會問為啥不配置?我這樣是為了直觀理解、這樣是為了直觀理解、這樣是為了直觀理解!!

class Order {
    public Guid id { get; set; }
    public string xxx { get; set; }

    public List<OrderDetail> Details { get; set; }
}
class OrderDetail{
    public Guid id { get; set; }
    public string detailTestField { get; set; }

    public Guid OrderId { get; set; }
}

Select<Order>().IncludeMany(a => a.Details.Where(b => b.OrderId == a.Id)).ToList();

OK,這樣查詢 order 時,會把 details 也查詢回來。

完結

我們有考慮在 then 那裡實現 limit(5) 功能,場景是隻查詢每個子記錄的前5條回來(待實現)。

開源地址:https://github.com/2881099/FreeSql

感謝一直支援的朋友們!

相關文章