.netEFCore專題:EFCore讀取數(shù)據(jù)是如何運(yùn)行的-創(chuàng)新互聯(lián)

本篇內(nèi)容主要講解“.net EF Core專題:EF Core 讀取數(shù)據(jù)是如何運(yùn)行的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“.net EF Core專題:EF Core 讀取數(shù)據(jù)是如何運(yùn)行的”吧!

成都創(chuàng)新互聯(lián)公司主營南靖網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都app軟件開發(fā),南靖h5微信小程序搭建,南靖網(wǎng)站營銷推廣歡迎南靖等地區(qū)企業(yè)咨詢

本文將為你詳細(xì)描繪 EF Core 從數(shù)據(jù)庫中讀取數(shù)據(jù)的“幕后”視圖。我將揭開兩種數(shù)據(jù)庫讀取方式的面紗:一個(gè)是普通的查詢,另一個(gè)是使用 AsNoTracking 方法的非跟蹤查詢。我還將通過一個(gè)實(shí)驗(yàn)來演示我是如何解決我的一個(gè)客戶遇到的性能問題。

我假設(shè)你對(duì) EF Core 已經(jīng)有了一定的認(rèn)識(shí),但在深入學(xué)習(xí)之前,我們先來了解一下如何使用 EF Core,以確保我們已經(jīng)掌握了一些基本知識(shí)。這是一個(gè)“深入研究”的課題,所以我準(zhǔn)備大量的技術(shù)細(xì)節(jié),希望我的描述方式你能理解。

本文是“深入理解 EF Core”系列中的第一篇。以下是本系列文章列表:

  • 當(dāng) EF Core 從數(shù)據(jù)庫讀取數(shù)據(jù)時(shí)發(fā)生了什么?(本文)

  • 當(dāng) EF Core 寫入數(shù)據(jù)到數(shù)據(jù)庫時(shí)發(fā)生了什么?(敬請(qǐng)期待)

概要


  • EF Core 有兩種方法從數(shù)據(jù)庫中讀取數(shù)據(jù)(也稱為查詢):普通 LINQ 查詢和包含 AsNoTracking 方法的非跟蹤 LINQ 查詢。

  • 這兩種方法查詢的返回類(被稱為實(shí)體類),它連接的其它的實(shí)體類(即所謂的導(dǎo)航屬性)也被同時(shí)加載,但這兩種法如何連接及連接的內(nèi)容是不一樣的。

  • 普通查詢接受的是 DbContext 執(zhí)行讀取時(shí)所有數(shù)據(jù)的副本——此時(shí)的實(shí)體類稱為被跟蹤。這允許加載的實(shí)體類參與數(shù)據(jù)庫的更新操作。

  • 普通查詢還會(huì)有一些其它的復(fù)雜底層實(shí)現(xiàn),稱為關(guān)系修補(bǔ)(fixup),用于描述讀入的實(shí)體類和其他被跟蹤實(shí)體之間的連接關(guān)系。

  • AsNoTracked 非跟蹤查詢沒有副本,所以它沒有被跟蹤——這意味著它比普通查詢更快。這也意味著它不會(huì)用于數(shù)據(jù)庫的寫操作。

  • 最后,我將展示 EF Core 普通查詢中一個(gè)鮮為人知的特性,以此作為示例,說明通過導(dǎo)航屬性連接實(shí)體類的關(guān)系是多么智能。


EF Core 如何讀取數(shù)據(jù)庫數(shù)據(jù)

提示:如果你已經(jīng)對(duì) EF Core 有一定的認(rèn)識(shí),那么你可以跳過這一節(jié),這部分只是一個(gè)如何讀取數(shù)據(jù)庫的例子。

為了能讓你更好地理解,我先描述一個(gè)數(shù)據(jù)庫結(jié)構(gòu),然后再給出一個(gè)簡單的數(shù)據(jù)庫讀取示例。下面是一些基本表的結(jié)構(gòu)和它們之間的關(guān)系。

.net EF Core專題:EF Core 讀取數(shù)據(jù)是如何運(yùn)行的

這些表被映射到具有類似名稱的類,例如 Book、BookAuthor、Author,這些類的屬性名稱與表的字段名稱相同。由于篇幅有限,我不打算展開來講這些類,但您可以在我的 GitHub 倉庫[1]中查看這些類。

EF Core 讀取數(shù)據(jù)庫需要下面五部分:

  1. 數(shù)據(jù)庫服務(wù)器,如 SQL server, Sqlite, PostgreSQL 等。

  2. 具有數(shù)據(jù)的數(shù)據(jù)庫。

  3. 映射到數(shù)據(jù)表的類(稱為實(shí)體類)。

  4. 一個(gè)繼承 DbContext 的類,該類包含 EF Core 的配置。

  5. 最后,從數(shù)據(jù)庫讀取數(shù)據(jù)的命令。

下面的單元測試代碼來自我的 GitHub 創(chuàng)庫[2],展示了一個(gè)簡單的示例,它從現(xiàn)有數(shù)據(jù)庫中讀取 4 個(gè) Book 實(shí)體及其關(guān)聯(lián)的 BookAuthor 和 Authors 實(shí)體。


[Fact]
public void TestBookCountAuthorsOk()
{
  //SETUP
  var options = SqliteInMemory.CreateOptions<EfCoreContext>();
  //code to set up the database with four books, two with the same Author
  using (var context = new EfCoreContext(options))
  {
    //ATTEMPT
    var books = context.Books
      .Include(r => r.AuthorsLink)
      .ThenInclude(r => r.Author)
      .ToList();

    //VERIFY
    books.Count.ShouldEqual(4);
    books.SelectMany(x => x.AuthorsLink.Select(y => y.Author))
      .Distinct().Count().ShouldEqual(3);
  }
}

現(xiàn)在,如果我們將單元測試代碼對(duì)應(yīng)到上面的 5 部分,結(jié)果是這樣的:

  1. 數(shù)據(jù)庫服務(wù)器——第 5 行:我選擇了一個(gè) Sqlite 數(shù)據(jù)庫服務(wù)器,在本例中是SqliteInMemory.CreateOptions方法,它使用我的一個(gè) NuGet 包 EfCore.TestSupport 創(chuàng)建了一個(gè)內(nèi)存數(shù)據(jù)庫(內(nèi)存中的數(shù)據(jù)庫對(duì)于單元測試非常有用,因?yàn)槟憧梢詾檫@個(gè)測試建立一個(gè)新的空數(shù)據(jù)庫)。

  2. 具有數(shù)據(jù)的數(shù)據(jù)庫——第 6 行:我將在下一篇文章介紹數(shù)據(jù)是如何寫入數(shù)據(jù)庫的,現(xiàn)在假設(shè)有一個(gè)數(shù)據(jù)庫包含 4 本書信息,其中兩本書的作者是同一個(gè)人。

  3. 實(shí)體類——代碼里這里沒有展示,但是你可以在這里查看這些類[1]。其中有一個(gè) Books 實(shí)體類,通過一個(gè)名為 BookAuhor 的實(shí)體類多對(duì)多關(guān)聯(lián) Authors 實(shí)體類。

  4. 一個(gè)繼承 DbContext 的類——第 7 行:EfCoreContext 類繼承了 DbContext 類并配置了從類到數(shù)據(jù)庫的映射關(guān)系(你可以在我的 GitHub 倉庫[3] 中查看該類)。

  5. 從數(shù)據(jù)庫讀取數(shù)據(jù)的命令——第 10 到 13 行,這是一個(gè)查詢:

  • 第 10 行 — context 為 EfCoreContext 的實(shí)例,通過它訪問你的數(shù)據(jù)庫,.Books表示您希望訪問 Books 表。

  • 第 11 行 — Include 被稱為貪婪加載,它告訴 EF Core 當(dāng)它加載 Books 時(shí),也應(yīng)該加載關(guān)聯(lián)到的所有 BookAuthor 實(shí)體類。

  • 第 12 行 — ThenInclude 是繼續(xù)貪婪加載,它告訴 EF Core 當(dāng)它加載一個(gè) BookAuthor 時(shí),它也應(yīng)該加載關(guān)聯(lián)到該 BookAuthor 的 Author 實(shí)體類。


所有這一切查詢出來是一個(gè)結(jié)果集,其中有普通屬性,像 Books 的 Title 屬性;有關(guān)聯(lián)實(shí)體類的導(dǎo)航屬性,像 Books 的 AuthorsLink 屬性。

這個(gè)示例稱為查詢或讀取,也是四種數(shù)據(jù)庫訪問類型之一,即 CRUD(新增、讀取、更新和刪除)。我將在下一篇文章中介紹新增和更新。

EF Core 如何表示讀取的數(shù)據(jù)


當(dāng)你查詢數(shù)據(jù)庫時(shí),EF Core 會(huì)將數(shù)據(jù)庫返回的數(shù)據(jù)轉(zhuǎn)換為實(shí)體類并填充導(dǎo)航屬性的值。在本節(jié)中,我們將研究兩種類型的查詢步驟——普通查詢(即沒有 AsNoTracking 方法,也稱為讀寫查詢)和添加了 AsNoTracking 方法的非跟蹤查詢(稱為只讀查詢)。

我們先來看一下最初 LINQ 語句是如何轉(zhuǎn)換成數(shù)據(jù)庫相應(yīng)的查詢命令然后返回?cái)?shù)據(jù)的。對(duì)于我們將要看到的兩種類型的查詢來說,這是很常見的操作。關(guān)于查詢的第一部分,請(qǐng)參見下圖。

.net EF Core專題:EF Core 讀取數(shù)據(jù)是如何運(yùn)行的

有一些非常復(fù)雜的代碼將你的 LINQ 轉(zhuǎn)換為數(shù)據(jù)庫查詢命令,但這些內(nèi)部細(xì)節(jié)我們不必關(guān)心。如果你的 LINQ 不能被翻譯,你會(huì)從 EF Core 得到一個(gè)異常消息,其中包含類似“不能被翻譯”的描述詞語。此外,當(dāng)數(shù)據(jù)返回時(shí),像 Value Converters[4] 這樣的特性可能會(huì)調(diào)整數(shù)據(jù)。

本節(jié)展示了查詢的第一部分,其中 LINQ 被轉(zhuǎn)換為數(shù)據(jù)庫命令并返回所有正確的值?,F(xiàn)在我們來看查詢的第二部分,在這里 EF Core 獲取返回值并將它們轉(zhuǎn)換為實(shí)體類的實(shí)例,并填充導(dǎo)航屬性。我們將分別看看兩種類型的查詢。

1. 普通查詢(讀寫查詢)


普通查詢讀取數(shù)據(jù)的方式可以修改數(shù)據(jù)并更新到數(shù)據(jù)庫,這就是我將其稱為讀寫查詢的原因。它不會(huì)自動(dòng)更新數(shù)據(jù)(請(qǐng)參閱下一篇文章,了解如何寫入數(shù)據(jù)庫)。如果你要更新數(shù)據(jù),你的查詢必須是讀寫查詢。

我在介紹中給出的示例執(zhí)行的是一個(gè)普通讀寫查詢,讀取帶有 AuthorsLink 實(shí)例的示例。下面是該示例的查詢部分的代碼:

var books = context.Books
  .Include(r => r.AuthorsLink)
  .ThenInclude(r => r.Author)
  .ToList();

然后 EF Core 通過三個(gè)步驟將這些值轉(zhuǎn)換并填充含有導(dǎo)航屬性的實(shí)體類。下圖顯示了這三個(gè)步驟以及生成的實(shí)體類及其導(dǎo)航屬性的實(shí)體類。

.net EF Core專題:EF Core 讀取數(shù)據(jù)是如何運(yùn)行的

讓我們來分析一下這三個(gè)步驟:

  1. 創(chuàng)建類并填充數(shù)據(jù)。它接受數(shù)據(jù)庫返回的值,并填充非導(dǎo)航(稱為標(biāo)量)屬性、字段等。在 Book 實(shí)體類中,是 BookId(主鍵)、Title 等屬性——參見上圖左下角淺藍(lán)色矩形。

  2. 修補(bǔ)關(guān)聯(lián)關(guān)系。首先是填入主鍵和外鍵的信息,它們定義如何相互關(guān)聯(lián)數(shù)據(jù)。然后,EF Core 使用這些鍵設(shè)置實(shí)體類之間的導(dǎo)航屬性(如圖中藍(lán)色粗線所示)。這個(gè)關(guān)系的修補(bǔ)所需的信息不僅是查詢讀入的實(shí)體類,它還會(huì)查看 DbContext 中跟蹤的每個(gè)實(shí)體,并填充導(dǎo)航屬性。這是一個(gè)強(qiáng)大的功能,但你的被跟蹤實(shí)體越多,所需消耗時(shí)間也越多——這就是為什么需要 AsNoTracking 來實(shí)現(xiàn)更快的查詢。

  3. 創(chuàng)建跟蹤快照。跟蹤快照是返回給用戶的實(shí)體類的一個(gè)副本,加上它所隱藏的與每個(gè)實(shí)體類的關(guān)聯(lián)關(guān)系——若一個(gè)實(shí)體處于被跟蹤狀態(tài),這意味著它將會(huì)發(fā)生修改并會(huì)寫入到數(shù)據(jù)庫中。


2. 非跟蹤查詢(只讀查詢)


非跟蹤查詢,即使用 AsNoTracking 方法的查詢,是一個(gè)只讀查詢。這意味著,當(dāng) SaveChanges 方法被調(diào)用時(shí),你讀取的任何內(nèi)容都不會(huì)被寫入數(shù)據(jù)庫。非跟蹤查詢的查詢效率更高,在下一節(jié)中,我將介紹非跟蹤查詢以及與普通查詢的其他區(qū)別。

在前文的示例之后,我修改了查詢代碼,添加了下面的 AsNoTracking 方法(請(qǐng)看第 2 行):

var books = context.Books
  .AsNoTracking()
  .Include(r => r.AuthorsLink)
  .ThenInclude(r => r.Author)
  .ToList();

這里的 LINQ 查詢只有上面的普通查詢的前兩個(gè)步驟(沒有第三個(gè)步驟)。下圖顯示了 AsNoTracking 查詢的步驟。

.net EF Core專題:EF Core 讀取數(shù)據(jù)是如何運(yùn)行的

步驟如下:

  1. 創(chuàng)建類并填充數(shù)據(jù)。它接受數(shù)據(jù)庫返回的值,并填充非導(dǎo)航(稱為標(biāo)量)屬性、字段等。在 Book 實(shí)體類中,是 BookId(主鍵)、Title 等屬性——參見上圖左下角淺藍(lán)色矩形。

  2. 修補(bǔ)關(guān)聯(lián)關(guān)系。首先是填入主鍵和外鍵的信息,它們定義如何相互關(guān)聯(lián)數(shù)據(jù)。然后,EF Core 使用這些鍵設(shè)置實(shí)體類之間的導(dǎo)航屬性(如圖中藍(lán)色粗線所示)。這個(gè)關(guān)系的修補(bǔ)所需的信息不僅是查詢讀入的實(shí)體類,它還會(huì)查看 DbContext 中跟蹤的每個(gè)實(shí)體,并填充導(dǎo)航屬性。這是一個(gè)強(qiáng)大的功能,但你的被跟蹤實(shí)體越多,所需消耗時(shí)間也越多——這就是為什么需要 AsNoTracking 來實(shí)現(xiàn)更快的查詢。


普通查詢和非跟蹤查詢的區(qū)別


現(xiàn)在讓我們比較這兩種查詢比較明顯的區(qū)別。

  1. 非跟蹤查詢查詢的性能更好。使用非跟蹤查詢查詢的主要原因是性能。非跟蹤查詢查詢表現(xiàn)為:

  • 稍微快一點(diǎn),使用的內(nèi)存稍微少一點(diǎn),因?yàn)樗恍枰獎(jiǎng)?chuàng)建跟蹤快照。

  • 避免沒有必要的跟蹤快照可以提高 SaveChanges 的性能,因?yàn)樗槐貦z查跟蹤快照以查找更改。

  • 稍微快一點(diǎn),因?yàn)樾扪a(bǔ)關(guān)聯(lián)關(guān)系時(shí)沒有所謂的身份解析。這就是為什么你會(huì)得到兩個(gè)具有相同數(shù)據(jù)的 Author 實(shí)例。


  1. 非跟蹤查詢修補(bǔ)關(guān)聯(lián)關(guān)系時(shí)只鏈接查詢中的實(shí)體。在普通查詢中,我已經(jīng)說過修補(bǔ)關(guān)聯(lián)關(guān)系時(shí)連接的是查詢中的實(shí)體和當(dāng)前跟蹤的實(shí)體,但是非跟蹤查詢只修補(bǔ)查詢中的實(shí)體關(guān)系。

  2. 非跟蹤查詢并不總是代表數(shù)據(jù)庫關(guān)系。這兩種類型查詢之間的關(guān)系修補(bǔ)的另一個(gè)區(qū)別是,非跟蹤查詢關(guān)系修補(bǔ)更快,它不需要標(biāo)識(shí)的解析。這可以為數(shù)據(jù)庫中的同一行生成多個(gè)實(shí)例——見上圖右下角藍(lán)色的 Author 實(shí)體和注釋。如果只是向用戶顯示數(shù)據(jù),那么這種差異并不重要,但是如果具有業(yè)務(wù)邏輯,那么多個(gè)實(shí)例不能正確反映數(shù)據(jù)的結(jié)構(gòu),就可能會(huì)有問題。

對(duì)層級(jí)數(shù)據(jù)有用的關(guān)系修補(bǔ)特性


關(guān)聯(lián)關(guān)系修補(bǔ)的步驟是非常智能的,特別是在普通查詢中。下面我想向你展示我是如何利用關(guān)系修補(bǔ)的特性來解決一個(gè)客戶項(xiàng)目中的性能問題的。

我曾在一家公司工作,那里的許多數(shù)據(jù)處理都是層次化結(jié)構(gòu)的,即數(shù)據(jù)具有一系列深度不確定的關(guān)聯(lián)關(guān)系。問題是我必須先解析整個(gè)層次結(jié)構(gòu),然后才能呈現(xiàn)這些數(shù)據(jù)。我最初是通過貪婪的方式加載前兩個(gè)層級(jí),然后顯式地加載更深的層級(jí)來實(shí)現(xiàn)這一點(diǎn)的。它可以工作,但是性能非常慢,并且數(shù)據(jù)庫因大量單數(shù)據(jù)庫訪問而超載。

這不得不讓我思考解決辦法,如果普通查詢的關(guān)系修補(bǔ)那么智能的話,它能幫助我提高查詢的性能嗎?它可以!讓我給你舉一個(gè)公司員工的例子。下圖顯示了我們想要加載的公司的層次結(jié)構(gòu)。

.net EF Core專題:EF Core 讀取數(shù)據(jù)是如何運(yùn)行的

你可以接龍式地使用 .Include(x => x.WorksForMe).ThenInclude(x => x.WorksForMe)… 等等來加載所需的層級(jí)信息,但結(jié)果是一個(gè) .Include(x => x.WorksForMe) 就夠了。因?yàn)?EF Core 的關(guān)系修補(bǔ)為你做了剩下的事情,這一點(diǎn)很驚奇,但也很有用。

例如,如果我想查詢角色為 Development 的所有員工(每個(gè)員工都有一個(gè)名為 WhatTheyDo 的屬性和名為 Role 的屬性,該 Role 包含他們工作的部門),我可以這樣編寫代碼:

var devDept = context.Employees
  .Include(x => x.WorksFromMe)
  .Where(x => x.WhatTheyDo.HasFlag(Roles.Development))
  .ToList();

 這將創(chuàng)建一個(gè)查詢,用于加載角色為 Development 的所有員工,并且在員工實(shí)體類上修補(bǔ)與 WorksFoMe 導(dǎo)航屬性(集合)和 Manager 導(dǎo)航屬性(單個(gè))的關(guān)系。通過只執(zhí)行一個(gè)查詢,既提高了查詢花費(fèi)的時(shí)間,又減少了數(shù)據(jù)庫服務(wù)器上的負(fù)載。

總結(jié)


你已經(jīng)看到了兩種類型的查詢,我稱之為 a)普通的讀寫查詢,和 b) 非跟蹤的只讀查詢。對(duì)于每一種查詢類型,我都向你展示了 EF Core “幕后”是如何讀取數(shù)據(jù)并展示的。他們工作方式的不同也表現(xiàn)出他們的優(yōu)勢和劣勢。

非跟蹤查詢是只讀查詢的解決方案,因?yàn)樗绕胀ㄗx寫查詢更快。但是您應(yīng)該記住關(guān)系修補(bǔ)的機(jī)制,它可以在數(shù)據(jù)庫只有一個(gè)關(guān)系的情況下創(chuàng)建類的多個(gè)實(shí)例。

普通的讀寫查詢是查詢跟蹤實(shí)體的解決方案,這意味著你可以在創(chuàng)建、更新和刪除數(shù)據(jù)時(shí)使用它們。普通的讀寫查詢確實(shí)會(huì)占用更多的時(shí)間和內(nèi)存資源,但是有一些有用的特性,比如自動(dòng)鏈接到其他被跟蹤的實(shí)體類實(shí)例。

到此,相信大家對(duì)“.net EF Core專題:EF Core 讀取數(shù)據(jù)是如何運(yùn)行的”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)建站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

網(wǎng)頁題目:.netEFCore專題:EFCore讀取數(shù)據(jù)是如何運(yùn)行的-創(chuàng)新互聯(lián)
文章位置:http://muchs.cn/article12/hoodc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計(jì)、做網(wǎng)站標(biāo)簽優(yōu)化、靜態(tài)網(wǎng)站、網(wǎng)站設(shè)計(jì)品牌網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)