[翻譯 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: 翻譯難免限於本人水平有不准確的地方,建議英文水平不錯的同學直接查看原版,有不足的地方歡迎指正

第一部分目錄導航

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

創建了MyFirstEfCoreApp應用程序后,你現在可以通過它查看EF Core的工作原理,重點不在於應用程序的代碼,而是在讀取和寫入數據到數據庫時EF Core內部會發生什么. 我的目標是讓你了解EF Core的工作機制,當你深入研究本書其余部分的命令時,這會很有幫助

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

數據庫建模

在對數據庫進行操作之前,EF Core必須進行數據庫建模. 數據庫建模是EF Core通過實體類和其他EF Core配置來描述數據庫的方法. EF Core在所有的數據庫訪問中使用建立的模型

建模在創建應用程序的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認為數據庫模型和實際的數據庫不匹配,就會出現問題

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

從數據庫中讀取數據

現在可以訪問數據庫了. 我們使用List(l)命令,讓程序讀取數據庫並在終端上打印信息. 圖1.7顯示了輸出

下面列出代碼清單, 用於將所有的圖書與作者輸出到控制台

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方法,否則會拋出異常


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM