[翻譯 EF Core in Action 1.9] 掀開EF Core的引擎蓋看看EF Core內部是如何工做的

Entity Framework Core in Action

Entityframework Core in action是 Jon P smith 所著的關於Entityframework Core 書籍。原版地址. 是除了官方文檔外另外一個學習EF Core的不錯途徑, 書中由淺入深的講解的EF Core的相關知識。由於沒有中文版,因此本人對其進行翻譯。 預計每兩天一篇更新 PS: 翻譯不免限於本人水平有不許確的地方,建議英文水平不錯的同窗直接查看原版,有不足的地方歡迎指正html

第一部分目錄導航

掀開EF Core的引擎蓋看看EF Core內部是如何工做的

建立了MyFirstEfCoreApp應用程序後,你如今能夠經過它查看EF Core的工做原理,重點不在於應用程序的代碼,而是在讀取和寫入數據到數據庫時EF Core內部會發生什麼. 個人目標是讓你瞭解EF Core的工做機制,當你深刻研究本書其他部分的命令時,這會頗有幫助git

注 書中僅給出了關鍵代碼, 完整示例在 https://github.com/JonPSmith/EfCoreInAction/tree/Chapter01

數據庫建模

在對數據庫進行操做以前,EF Core必須進行數據庫建模. 數據庫建模是EF Core經過實體類和其餘EF Core配置來描述數據庫的方法. EF Core在全部的數據庫訪問中使用創建的模型github

建模在建立應用程序的DbContext時就開始了,在本例中是AppDbContext(如圖1.5所示,在上一篇文章中). 它有屬性DbSet ,使得經過代碼能夠訪問數據庫 數據庫

圖1.6描述了建模過程的概述,它會幫助你理解EF Core數據庫建模的過程. 後續的章節將介紹一系列配置數據庫的相關命令,在本文中使用默認配置緩存

圖1.6展現了EF Core在AppDbContext的建模步驟,下文對此過程進行更詳細的說明學習

  1. EF Core查看DbContext並找到全部公共的DbSet 屬性,並使用屬性名爲表定義初始名稱.
  2. EF Core查看DbSet 的泛型類,查看類的屬性構建列名,類型等. 它還會查找類和屬性用於提供額外建模配置的特殊Attribute
  3. EF Core查找DbSet 類中引用的其餘類. 在咱們的例子中Book類有一個對Author類的引用,因此EF Core也會查看它. 它對Author類執行與步驟2相同的操做. 同時它使用類名Author作爲表名
  4. 建模過程的最後一個步驟, EF Core運行DbContext的虛方法OnModelCreating, 能夠經過重寫OnModelCreating方法使用fluent Api進行更多的建模配置,但本例中爲了保持示例的簡單並無這樣作
  5. EF Core根據收集的信息建立數據庫的內部模型,並緩存數據庫模式,以便提高訪問速度. 在以後的全部的數據庫訪問中使用此模型

你可能會注意到圖1.6並無展現數據庫,由於EF Core構建內部模型時,它不會去查看數據庫. 我強調這一點是爲了說明構建一個的數據庫模型多麼重要,若是EF Core認爲數據庫模型和實際的數據庫不匹配,就會出現問題.net

在你的應用程序中你可使用EF Core來建立數據庫,這會避免出現不匹配的狀況. 若是你想要一個良好且高效的數據庫,那麼在你的代碼中編寫良好的數據庫模型是很是重要的,這樣建立的數據庫會是高效的. 建立,更新和管理數據庫結構是一個很大的主題,將在11章詳細介紹翻譯

從數據庫中讀取數據

如今能夠訪問數據庫了. 咱們使用List(l)命令,讓程序讀取數據庫並在終端上打印信息. 圖1.7顯示了輸出3d

下面列出代碼清單, 用於將全部的圖書與做者輸出到控制檯code

EF Core使用Linq(語言集成查詢)執行它想要執行的命令,使用.net類保存數據

代碼清單中粗體顯示的兩行代碼進行了數據庫訪問. 下面讓咱們看看EF Core如何使用Linq代碼訪問數據庫並返回數據. 圖1.8跟隨着這些代碼走進EF Core內部,看看鮮爲人知的故事...

從數據庫中讀取數據的過程以下

  1. Linq查詢中的db.Books.AsNoTracking().Include(a => a.Author)訪問應用程序DbContext的DbSet 屬性, Include(a => a.Author)顯式加載關係的Author部分. 數據庫提供程序將Linq翻譯成訪問數據庫的SQL命令. SQL被緩存以便若是再次使用相同的查詢語句時避免從新翻譯的成本
    EF Core在數據庫訪問方面會盡量高效. 在這種狀況下,它將須要讀取的兩張表(Books和Author)組合到一個大表中,在一次數據庫訪問中完成工做. 下面的清單展現了EF Core和數據庫提供程序建立的SQL
    SELECT [b].[BookId], [b].[AuthorId], [b].[Description], [b].[PublishedOn], [b].[Title], [a].[AuthorId], [a].[Name], [a].[WebUrl] FROM [Books] AS [b] INNER JOIN [Author] AS [a] ON [b].[AuthorId] = [a].[AuthorId]
  2. 數據庫提供程序讀取數據後,EF Core經過如下過程放置數據: (a) 建立.NET類的實例 (b) 使用數據庫關係連接(外鍵),經過引用(稱爲關係修復)將.NET類連接在一塊兒. 結果是一組以正確方式連接的.NET類實例. 在本例中兩本書有相同的做者Martin Fowler,所以這兩本書的做者屬性指向同一個Author類
  3. 因爲代碼中包含 AsNoTraching, 因此EF Core知道禁止建立跟蹤快照. 跟蹤快照用於發現數據的變化, 你會在編輯WebUrl的示例中瞭解這一點. 因爲這是一個只讀查詢,所以禁用跟蹤快速會使查詢更快

更新數據庫

如今使用MyFirstEfCoreApp中的第二個命令update(u)來更新圖書Quantum Networking做者的WebUrl列. 如圖1.9所示,首先列出全部書籍,會看到最後一本書的做者沒有WebUrl. 而後運行命令u,它將要求輸入Url. 這時輸入 httqs://entangled.moon(這是一個虛構的Url,httpqs-.-),在更新成功後再次列出全部的書籍,這時能夠看到Web Url值已經更新

代碼清單

圖1.10展現了EF Core內部發生了什麼並跟蹤其進度,這比上一個read的示例複雜許多, 所以我會給你一些提示

圖頂部的讀取階段與上一個讀取示例相似,因此應該很熟悉. 在此基礎上使用圖書的標題作爲過濾器載特定的圖書. 重要的是第2點: 對數據進行跟蹤

在圖的下半部分你能夠看到EF Core如何將加載的數據與跟蹤快照進行比較並找到更改,能夠看到只有WebUrl被更新了,它建立了一個SQL命令來只更新該列

圖中已經描述了大部分步驟,下面介紹Author的WebUrl列如何更新的詳細說明

  1. 應用程序使用LINQ查找包含做者信息的單個圖書,EF Core將LINQ查詢翻譯爲SQL命令,讀取Title爲Quantum Networking的行,返回Book和Author類的實例,由於使用了Single查詢,因此還會檢查是否只找到一行
  2. LINQ查詢中沒有AsNoTracking方法,因此該查詢是一個具備跟蹤的查詢,EF Core建立了數據的跟蹤快照
  3. 而後代碼更改了Book的Author的WebUrl屬性. 當調用SaveChanges時, 檢測更改階段會將跟蹤的全部類與跟蹤快照進行比較. 在這裏它會檢測到全部已更改的內容. 在本例中主鍵爲3的Author實例的WebUrl屬性值被更改
  4. 檢測到更改後,EF Core將啓動事務. 每一個數據庫更新都以原子單位完成: 更改所有成功或者所有失敗. 這很是重要,由於若是僅應用了部分更改,關係數據庫可能會發生嚴重的錯誤
  5. 更新請求由數據庫提供程序轉換爲SQL命令,若是執行成功則提交事務並返回SaveChanges方法,不然會拋出異常
相關文章
相關標籤/搜索