ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案,早期被称为 ObjectSpace,由于原生的ADO效率低下等原因,一些ORM框架出现在我们的面前,今天给大家介绍的就是C#大名鼎鼎的EF框架。
Entity Framework7简称EF7,是微软正在开发的最新的在.NET应用中首选的数据访问技术。它是轻量级和可扩展的启用新的平台和新的数据存储的实体框架版本。以下的应用: Windows Phone、 Windows 应用商店,ASP.NET 5 和传统的桌面应用程序,现在都可以利用的实体框架。EF7除了支持关系型数据库, 还支持如 Azure 表和Redis非关系型数据存储。
从上面我们可以看到以下几个重点:
EF7跟之前版本一样,仍然是一项数据访问技术;
EF7是一个轻量的可扩展的的实体框架;轻量是相较之前的版本,之前的版本因为众多的遗留问题(比如上下文对象就有ObjectContext和DbContext两个版本)和之前设计上的一些问题,已经非常复杂和庞大了,其中包含了使用上的复杂性。EF7是一次重大的变革,微软决定从头重构它;
EF7支持非关系数据存储了;
1、与之前的版本有哪些是相同的?
使用它时,顶层的接口跟之前的版本基本相同
a、你仍然可以继承DbContext上下文对象,上下文中仍有DbSet
b、你仍然可以在DbSet属性上使用Linq来编写查询;
c、你仍然可以使用DbSet属性上的Add和Remove方法;
d、你仍然可以使用DbContext.ChangeTracker和DbContext.Database属性访问对象跟踪和调用数据库相关的 api;
例如:下面的代码在EF6.x和EF7中写法一样
using (var db = new BloggingContext()) { db.Blogs.Add(new Blog { Url = "blogs.msdn.com/adonet" }); db.SaveChanges(); var blogs = from b in db.Blogs.Include(b => b.Posts) orderby b.Name select b; foreach (var blog in blogs) { Console.WriteLine(blog.Name); foreach (var post in blog.Posts) { Console.WriteLine(" -" + post.Title); } } }
2、有哪些改变?
A、新特性
a、支持对关系型数据的批量更新。 什么意思就不用细说了吧,在这之前,很多人喷粪EF,就是说他的更新效率太低,如果要实现批量更新,特别插入时,需要借助sql语句或是第三方工具类。相信这是很多人期待的功能;
b、支持唯一约束。它允许你在实体内除主键外额外标识一个键,将他们用作外键。
B、行为(Behavior)改变
EF6和前期的版本中,顶层API就有很多不直观的行为,虽然EF7尽可能是保持顶层API的相同,但仍去掉了一些限制并添加了一些我们期待的行为。什么意思呢?这听起来有点迷糊,举个例子来说明吧,以前的查询,虽然Linq给我们带来了很大方便,但限制多呀,整个Linq查询翻译成一条单独的sql查询,Linq查询中只能包含EF能翻译成sql的语句或方法;还有就是sql的生成,有时生成了很复杂、效率不高,且不是我们希望的sql语句。EF7改变这种情况,可以返回多结果集,sql评估工作也不是在数据库端来做了,变更到客户端。这样就为生成sql提供了很大的灵活性。如果还有点晕,没关系,先有个印象就行。
C、变得更加简单、灵活
直接使用一个例子来说明吧。我们想通过EF的元数据来获取Blog实体被映射到数据库中的哪一张表。在这之前,我们的代码会是这样:
using (var context = new BloggingContext()) { var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace; var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace)); var entityType = metadata .GetItems(DataSpace.OSpace) .Single(e => objectItemCollection.GetClrType(e) == typeof(Blog)); var entitySet = metadata .GetItems (DataSpace.CSpace).Single() .EntitySets .Single(s => s.ElementType.Name == entityType.Name); var mapping = metadata.GetItems (DataSpace.CSSpace).Single() .EntitySetMappings .Single(s => s.EntitySet == entitySet); var table = mapping .EntityTypeMappings.Single() .Fragments.Single() .StoreEntitySet; var tableName = (string)table.MetadataProperties["Table"].Value ?? table.Name; }
在EF7中会代码会是这样:
using (var db = new BloggingContext()) { var tableName = db.Model.GetEntityType(typeof(Blog)).Relational().Table; }
D、去掉了一些特性
a、每类型映射多个实体集(MEST)。这个特性,估计用的人很少,正是因为使用的人少,所以才去掉。它是什么意思呢?就是一个类型对应数据库中的多张表,例如:表Product 和 RetriedProduct都映射到Product类。如果你还有这样的需求,使用继承是更好的选择。
b、非常复杂的类型映射。在EF6.x中,可能在一个继承映射中组合TPH,TPT和TPC。EF7不再支持这种复杂的映射了,它要求你的CLR 类型尽量跟表结构保持一至。至于为什么,我相同不少人到现在都还没有弄明白什么是TPH,TPT,TPC,那更说不上灵活运行了,这也是导致EF6.x MetadataWorkspace异常复杂的主原之一。
c、去掉edmx建模。这可能会让很多人失望,因为它曾经给我们带来多么美好的回忆。但它有很多的不足,比较一些复杂的需求,不适应ddd分层设计,不符合现在流行的POCO等。最主要的是,有更好的选择code-based建模,这就是我们常说的code-first。 可能你会有疑问,怎么code-first和edmx是平级概念,它不是跟db-first、model-first平级的吗? 没错,它是跟edmx平级的,更详细的解释请查看我的另一篇博客Code First is a bad name,这些年我们对Code First的理解都错了 !很震惊吧?
d、ObjectContext API。它陪着EF一起成长,到EF4.1时才被DbContext弄到幕后.不过DbContext只是它的外观模式,底层仍然是使用的它。有时需要使用一些高级的功能时,我们还得想办法把它找出来。去掉它并不意味着它以前的一些功能不能用了。EF7重写了底层,把之前一定需要ObjectContext才能使用的api包含在了DbContext中,并且让调用更加清晰,简单。
e、延迟加载。 这功能相信大家不陌生,它一直被当成EF的一大特点,但现在,它将要从EF7中去掉。我不确定最终的版本微软会不会把它请回来,因为这一点存在很大的争论。无论是我们这些开发人员,还是EF的开发团队。我个人是支持去掉的。一,不是所有的应用都需要延迟加载;二、不少的EF使用者对它没有深入的去了解,经常会有人问,为什么会出现"无法完成该操作,因为 DbContext 已释放"这样的问题。这说明这个功能反而给一部份使用者带来了困惑。
这些变化并不是最终的,也许文中说的,会发生改变。当然这里也不可能列出所有的变化点,毕竟EF7还在处于开发过程中。总之,它是一个革命性的版本,以至于有人在争论应该叫他EF7呢,还是EF1。
E、对非关系型数据库的支持,文章开头部分已经有提到,这里就不多说了;
F、官方支持SQLite; 这估计对很多开发人员来说是福音,至少,这之前我为了使用Linq to Sqlite 折腾了不少时间,在博客园的处女作就为他而生 Linq To Sqlite 。
相信,很多人和我一样,去年就开始期待EF7的发布。一年多长长的等待,可是它还没有出来,到底要什么时候呢?微软的计划是2016年,所以大家还得耐心等待。不过,有个好消息是,它是开源的,最新的源代码在github上,如果你想了解更多的细节,可以到下面的地址(https://github.com/aspnet/EntityFramework)去克隆或是下载源代码。
现在回头来看这些ORM框架,你会觉得很强大,如果你真的对技术有研究的话,推荐你可以看一下它们的源代码,也许你会发现一些其他不一样的东西,这也许对于提升你的技术有很大的帮助。