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的模組化步驟,下文對此過程進行更詳細的說明
- EF Core檢視DbContext并找到所有公共的DbSet屬性,并使用屬性名為表定義初始名稱.
- EF Core檢視DbSet的泛型類,檢視類的屬性建構列名,類型等. 它還會查找類和屬性用于提供額外模組化配置的特殊Attribute
- EF Core查找DbSet類中引用的其他類. 在我們的例子中Book類有一個對Author類的引用,是以EF Core也會檢視它. 它對Author類執行與步驟2相同的操作. 同時它使用類名Author做為表名
- 模組化過程的最後一個步驟, EF Core運作DbContext的虛方法
, 可以通過重寫OnModelCreating
方法使用fluent Api進行更多的模組化配置,但本例中為了保持示例的簡單并沒有這樣做OnModelCreating
- 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内部,看看不為人知的故事...
從資料庫中讀取資料的過程如下
- Linq查詢中的
通路應用程式DbContext的DbSet屬性,db.Books.AsNoTracking().Include(a => a.Author)
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]
- 資料庫提供程式讀取資料後,EF Core通過以下過程放置資料: (a) 建立.NET類的執行個體 (b) 使用資料庫關系連結(外鍵),通過引用(稱為關系修複)将.NET類連結在一起. 結果是一組以正确方式連結的.NET類執行個體. 在本例中兩本書有相同的作者Martin Fowler,是以這兩本書的作者屬性指向同一個Author類
- 由于代碼中包含
, 是以EF Core知道禁止建立跟蹤快照. 跟蹤快照用于發現資料的變化, 你會在編輯WebUrl的示例中了解這一點. 由于這是一個隻讀查詢,是以禁用跟蹤快速會使查詢更快AsNoTraching
更新資料庫
現在使用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列如何更新的詳細說明
- 應用程式使用LINQ查找包含作者資訊的單個圖書,EF Core将LINQ查詢翻譯為SQL指令,讀取Title為Quantum Networking的行,傳回Book和Author類的執行個體,因為使用了
查詢,是以還會檢查是否隻找到一行Single
- LINQ查詢中沒有
方法,是以該查詢是一個具有跟蹤的查詢,EF Core建立了資料的跟蹤快照AsNoTracking
- 然後代碼更改了Book的Author的WebUrl屬性. 當調用SaveChanges時, 檢測更改階段會将跟蹤的所有類與跟蹤快照進行比較. 在這裡它會檢測到所有已更改的内容. 在本例中主鍵為3的Author執行個體的WebUrl屬性值被更改
- 檢測到更改後,EF Core将啟動事務. 每個資料庫更新都以原子機關完成: 更改全部成功或者全部失敗. 這非常重要,因為如果僅應用了部分更改,關系資料庫可能會發生嚴重的錯誤
- 更新請求由資料庫提供程式轉換為SQL指令,如果執行成功則送出事務并傳回SaveChanges方法,否則會抛出異常