寫這篇博客的時候,聽聞EF7都發布半年了,吐糟下巨硬,同時對自己老處在追趕者的角色深感不滿。
言歸正傳,提起DbContext就不得不提ObjectContext,在EF第一個版本發布以來,其中最重要的組件就是ObjectContext,ObjectContext提供了概念上的模型來讓我們與數據庫交互(寫查詢表達式、執行查詢,跟蹤模型修改狀態,持久化修改到數據庫),他同時也與其他重要的EF類來進行交互操作:
- ObjectSet:在內存中對實體進行集合操作。
- ObjectQuery:針對概念模型的類型化查詢。
所有這些類充滿了特性和功能--有的很復雜,大多數只在特殊情況下是必須的。在經歷了Entity Framework的兩個版本之后(.NET 3.5 SP1 .NET 4)逐漸明確了,開發者大部分只會用到這些功能的一部分,但不幸的是,對於我們經常做的大部分的任務編碼以及查詢都有點困難。
意識到這一點之后,EF團隊開始對開發者有愛了,他們的解決方案是創建了一些新類封裝了ObjectContext功能的子集,開發者在一般情況下就無需與ObjectContext打交道了(除了一些高級主題),這些新類是隨同EF4.1一起發布,是EF4.1的一部分。
這些新類就是指:DbContext,DbSet,DbQuery。同時他們是DbContext API 的一部分。這個新的API 不僅僅包含DbContext,而且包含了EF團隊為其開發的一些新的功能。DbContext API 是包含在Entity Framework.dll中的,這個類庫同時也包含了驅動Code First開發的邏輯,這個類庫與.NET是分開的,被發布在EntityFramework NuGet package。Entity Framework的主要部分是.NET Framework一部分(主要是System.Data.Entity.dll)。被包含在.NET Framework里面的這些組件被認為是Entity Framework“核心組件”,而DbContext API是完全獨立的,與這些“核心組件”是分開的。Entity Framework團隊意識到集成在.NET Framework里面不是一個好的選擇,他們正致力於把更多的“核心組件”從.NET Framework中移到到Entity Framework.dll中,這樣發布新的Entity Framework的新功能都無需等到.NET Framework新版本發布。
下表是DbContext API 的功能概覽
| DbContext API 類/功能 |
相關的EF4 類/功能 |
目的 | DbContext API 優點 |
| DbContext | ObjectContext | 代表與數據庫連接的會話,提供了查詢、狀態跟蹤、保存等功能 | 簡化了大部分ObjectContext功能 |
| DbSet | ObjectSet | 對實體類型提供了集合操作,比如Add、Attach、Remove。 繼承了DbQuery,所以可以提供查詢功能 |
簡化了大部分ObjectSet功能 |
| DbQuery | ObjectQuery | 提供查詢功能 | DbQuery的查詢功能集成在DbSet中, 所以不用直接操作DbQuery |
| Change Tracker API |
ObjectContext. ObjectStateManager |
獲得實體變化跟蹤信息以及相關的操作(original values、current values) 受上下文管理 |
更簡單、更直觀的API |
| Validation API | N/A | 提供自動的數據驗證。這個API 利用了.NET 4原生的驗證功能 | 新的 |
| Code First Model Building | N/A | 基於已有的類以及配置信息來創建數據庫及其元數據 | 新的 |
如何在自己項目中使用DbContext API
通過巨硬的NuGet 以及Library Package Manager 上下載Entity Framework組件,然后一切交給宇宙第一神IDE吧。
DbContext API的一些亮點
讓我們看看DbContext API 是如何來減少工作量的,如何減少當然要以ObjectContext來對比。
示例中包含Person Destination Trip三個實體
Example 1-1 ObjectContext寫法
1 public class BreakAwayContext : ObjectContext 2 { 3 private ObjectSet<Person> _ people; 4 private ObjectSet<Destination> _destinations; 5 private ObjectSet<Trip> _trips; 6 public ObjectSet<Person> People 7 { 8 get { return _people ?? (_people = CreateObjectSet<Person>("People")); } 9 } 10 public ObjectSet< Destination > Contacts 11 { 12 get { return _ destinations?? (_destinations = 13 CreateObjectSet< Destination >("Destinations")); } 14 } 15 public ObjectSet<Trip> Trips 16 { 17 get { return _ trips?? (_trips = CreateObjectSet<Trip>("Trips")); } 18 } 19 }
Example 1-2 DbContext 寫法
1 public class BreakAwayContext : DbContext 2 { 3 public DbSet<Person> People { get; set; } 4 public DbSet<Destination> Destinations { get; set; } 5 public DbSet<Trip> Trips { get; set; } 6 }
簡化以及優化一目了然。
減少以及簡化了集合操作
在Entity Framework 4中,添加實例到實體集中,你可以使用ObjectContext.AddObject或者ObjectSet.AddObject.當添加實例到ObjectContext中的時候,ObjectContext需要知道這個實例屬於哪個實 體集合,所以對於ObjectSet.AddObject你必須以文本的形式指明實體集名稱,比如:
context.AddObject("Trips",newTrip);
使用ObjectSet.AddObject的話稍微簡化點:context.Trips.AddObject(newTrip);至於ObjectContext.AddObject繼續存在於EF4的原因在於與早期版本的向后兼容性,但開發者並不會意識到這個原因, 只會被這兩種寫法搞迷糊了。
因為DbContext API是新的,我們無需擔心與早期版本的向后兼容性,所以DbContext並沒有提供在context上面添加實例的方法,只是在DbSet上面添加了Add方法:
context.Trips.Add(newTrip);
ObjectContext還提供了AttachObject和DeleteObject方法,同樣的DbContext並沒有提供類似的方法,這些方法全部在DbSet上面提供:Attach、Remove。
使用ID與DbSet.Find檢索一個實體
開發者經常要做的一件事就是根據key來查詢相應的實體,EF4時代我們都是寫如下的查詢語句:
context.People.SingleOrDefault(p=>p.Id=Id);
現在DbSet提供了Find方法:
context.People.Find(Id);
使用Find有個優點,調用SingleOrDefault方法會一直查詢數據庫,而使用Find方法,會首先查詢內存中是否存在相關實例,如果有,直接返回,如果沒有才會去查詢數據庫,對性能提高是大大的。
-------To Be Continue.
