写这篇博客的时候,听闻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.