对实体框架的下一版本的开发正在顺利进行中。我在 2014 年度北美 TechEd 上第一次了解 EF 团队的工做内容,当时项目经理 Rowan Miller 讨论了 Entity Framework 7 (EF7) 的目标并展现了一些早期的信息。git
那是我撰写此专栏的 5 个月以前,虽然 EF7 仍处于早期 Alpha 测试阶段,但已经取得了很大的进展。在本专栏中,我但愿您能了解到 EF7 会给开发人员带来什么、有关 EF7 的决定背后的动机以及此版本对使用 EF6 或更低版本的现有应用的意义。我还会向您展现其中的部分代码。github
首先请了解,EF7 和 EF6 同样,是开放源代码。但 EF7 以及 ASP.NET 的即将发布版本的剩余部分是在 GitHub 上而不是在 CodePlex 上开发的。EF7 开发的 URL 为 github.com/aspnet/EntityFramework。和 EF6 同样,您能够查看 EF7 发展过程的详细信息。您能够经过分支和提交探索源代码及其进度、关注讨论、提出问题、派生源代码以及提交团队的 pull 请求以进行检查并在可能时提交到代码库。算法
切勿担忧,不会强制您迁移到 EF7。回想一下 ADO.NET DataSets 和 DataReaders。与仍受支持甚至从偶尔的调整中受益的 ASP.NET Web 窗体很是像,ADO.NET 仍然是 Microsoft .NET Framework 的一部分,即便多年以来 EF 已经成为 .NET 的主要数据访问技术。尽管已再也不为加强这些技术采起任何措施,但它们仍然存在,而且支持不少旧代码(包括个人代码)。与其余技术相比,EF6 的一个巨大优点在于它是开放源代码,所以尽管 Microsoft 团队已再也不对 EF6 作大型投资,但社区仍会进行投资。并且,EF 团队仍在致力于 EF6。他们将继续进行调整,仔细检查 pull 请求,并更新 EF6。尽管他们在 2014 年的大部分时间里全身心地致力于 EF7,但也更新了 EF6。2014 年 2 月发布了版本 6.1.0;2014 年 6 月发布了版本 6.1.1;我在撰写本文时,版本 6.1.2 正处于测试中,即将发布。我最初很担忧旧版本的应用是否能继续运行,但如今再也不有此顾虑。我如今只担忧那些结合使用 EF 和 .NET Framework 3.五、ObjectContext 等程序的最低版本的应用。可是,若是您还没有更新这些应用以使用这些年来对 EF 作出的全部改进,则无需过多担忧 EF7。您能够在 NuGet 上找到 EF 的全部较低版本的包,能够一直追溯到 EF 4.1.10311。数据库
EF7 新增功能的高级概述以下:架构
EF 的每一个版本都在不断完善框架,添加新功能,并对性能和 API 进行微调。正如之前我在本专栏中以及在 2013 年 12 月发布的概述文章《Entity Framework 6:The Ninja Edition》(bit.ly/1cwjyCD) 中写道,最新版本的 EF 已经进入一个新的级别,框架新增了不少用户求之不得的功能,例如异步数据库执行、使用查询管道以及自定义代码优先约定等。在个人 Pluralsight 课程“Entity Framework 6, Ninja Edition:EF6 中的新功能”(bit.ly/PS-EF6) 中,我更深刻讨论了这些功能。框架
还有更多功能是开发人员但愿在 EF 中找到的且 Microsoft 但愿实现的,但用于构建 EF 的已 10 多年的代码库仍继续依赖 ObjectContext,且编码模式不够灵活,所以阻碍了该团队开发更高级的功能。所以作出了一个艰难的决定,即从头开始从新构建实体框架,而大部分人在面对本身的旧版本软件时固然也会面临一样的难题。异步
EF7 并不是为数据访问建立新的框架。而是构建一个新的、可持续性更高的库,该库不只支持您多年来依赖于 EF 的功能和工做流,还支持不少新功能。团队还在争论该产品应该是下一代 EF 仍是新的数据访问技术。我一度怀疑它是否应该是“EF 精简版”。可是,EF 的核心功能仍然存在,所以通过几番思考以后,我认为将其视为实体框架的下一个版本比较有意义。您能够在团队博文《EF7 – v1 或 v7?》(bit.ly/1EFEdRH) 中了解更多详细信息。ide
对于一些开发人员而言,也有一些关于 EF7 的消息使人不安。虽然大部分经常使用的 EF 类、模式和工做流将被完整保留,可是一些较少使用的成员将被抛弃。可是,请勿惊慌;我将详细地讨论这一问题。函数
让开发人员继续使用熟悉的模式,甚至可以将大量的现有代码移植到 EF7 中是关键目标。您仍可使用 DbContext、DbSet、LINQ 查询、SaveChanges 和早已成为 EF 一部分的不少交互方式。工具
我在 EF7 中定义的 DbContext 类以下:
public class BreweryContext : DbContext { public DbSet<Brewery> Breweries { get; set; } public DbSet<Beer> Beers { get; set; } }
此外,如下是 EF7 中的一个简单更新,和 EF6 同样。我使用的是同步保存,但也提供全部异步方法:
public void StoreBeers(List<Beer> beers) { using (var context = new BreweryContext()) { context.Beers.AddRange(beers); context.SaveChanges(); } }
一个简单查询以下:
using (var context = new BreweryContext()) { return context.Breweries.Where(b=>b.Location.Contains("Vermont")); }
我使用的 EF7 版本位于包含版本 beta2-11616 的包中。尽管如今 EF7 实际上还未处于测试阶段,可是“beta2”与 NuGet 包命名决定有关。截至本文发布时为止,EF7 又获得了进一步完善。所以,请注意上述内容只是大概介绍,并不是保证。
正如我一直所作的那样,我仍然拥有 DbContext,且定义了 DbSets。OnModelCreating 也仍然在,只是我没有在本例中使用。
EF4.1 中引入了 DbContext API,其更专一于 EF 的典型用法。实际上,它仍然依赖于原始 ObjectContext,由于 ObjectContext 可提供数据库交互、管理事务并跟踪对象状态。从那时起,DbContext 成为了使用的默认类,若是您但愿与 ObjectContext 的交互较少,则能够降低到较低级别的 API。EF7 将抛弃冗余的 ObjectContext;只保留 DbContext。但部分依赖于 ObjectContext 的任务仍可访问。
一些难以支持且不常使用的极其复杂的映射将在 EF7 中消失。正如上述博文中所述:“例如,您能够拥有将 TPH、TPT 和 TPC 映射以及 Entity Splitting 组合在同一层次结构中的继承层次结构。”若是您曾经尝试直接使用 MetadataWorkspace API,并尖叫着跑开了,您将会发现它是一个错综复杂的怪物,可用于支持这种灵活性。可是这种复杂性将阻碍团队支持用户请求的其余方案。经过简化映射的可能性,MetadataWorkspace API 也变得更加简单和灵活。您能够轻松地从 EF7 中的 DbContext API 中获取有关模型架构的元数据,其可赋予您执行高级技术的低级功能,而无需处理低级的 ObjectContext。
实体框架当前使用两种方法来描述模型。一种使用设计器中的 EDMX;另外一种涉及类,即代码优先 API 使用的 DbContext 和映射。若是您使用的是 EDMX 和设计器,则运行时 EF 会在 EDMX 后从 XML 中建立内存中模型。若是您选择代码优先路径,则 EF 会经过读取类(即您提供的 DbContext 和映射)来建立相同的内存中模型。从那之后 EF 的工做方式是相同的,不管您如何描述模型。请注意,经过 EDMX/设计器工做流,您还能够获取 POCO 类和 DbContext 供您在代码中使用。可是因为 EDMX 的存在,所以不会使用它们来建立该内存中模型。当您阅读下文时,理解很重要:EF7 将不支持基于设计器的 EDMX 模型。它没法在运行时读取 EDMX XML 来建立内存中模型。它将只使用代码优先工做流。
当团队发表有关这方面的博文时,引发了不少开发人员的恐慌。部分缘由是不少开发人员还没有意识到能够将数据库反向工程到 POCO 类、DbContext 和映射。换言之,您能够从数据库开始来获取代码优先模型。能够经过 2011 年初首次发布的 EF Power Tools Beta 来实现这一目的。该工具受 EF6.1 设计器支持,且确定也会受 EF7 支持。我已屡次提到“代码优先”这一名称有一些迷惑性和误导性。最初它称为“仅限代码”,后来这一名称改成“代码优先”以完美匹配“数据库优先”和“模型优先”。
所以,要从现有数据库开始,您无需设计器或 EDMX。
可是,若是您拥有现有 EDMX 模型,而且不想失去使用设计器的能力,会怎样呢?有一些第三方设计器支持实体框架,例如早已支持 EF 代码优先的 LLBLGen Pro Designer (bit.ly/11OLlN2) 以及 Devart Entity Developer (bit.ly/1yHWbB2)。查找可能提供支持 EF7 的设计器的工具以及其余可能的软件。
还要记住另外一个方法:坚持使用 EF6!
此外,Microsoft 还致力于简化 EF API 的分发。EF6.1.1 的 NuGet 包文件夹大约 22MB。包括 5.5MB 的 .NET Framework 4.5 程序集和其余内容(若是您使用 .NET Framework 4)。对于 EF7,有一些较小的 DLL。您能够仅组合支持工做流所需的 DLL。例如,若是针对 SQL Server,则使用核心 EntityFramework.dll、针对 SQL Server 的 DLL 以及包含关系数据存储共用的 API 的 DLL。若是要使用迁移,则您能够跳过该单独程序集。不然,您可能要从包管理器控制台建立并执行迁移。有一个适用于命令的 API。经过 NuGet 包管理器,能够经过包依赖关系识别并下载适当的包,所以您无需过于担忧其详细信息。
其做用是尽可能减小 EF7 在最终用户的计算机或设备上的占用空间,这对全部设备而言都很是重要。ASP.NET 也采用此方法。这两种技术都摆脱了对完整 .NET Framework 的依赖。相反,它们将只分发完成给定应用程序的任务所需的 DLL。这意味着 Windows Phone 和 Windows Store 应用商店应用使用的简化版本的 .NET 可使用 EF7。
这还意味着,使用 Mono 而非完整 .NET Framework 的 OS X 和 Linux 等操做系统也能够支持客户端实体框架。
第一次引入实体框架时,Microsoft 的愿景是将它应用于多种数据存储,尽管第一次是应用于关系数据库。和如今广受欢迎的 NoSQL 数据库(尤为是文档数据库)不一样,当时也存在非关系数据库,但并未普遍使用。
尽管 EF 是对象关系映射 (ORM),但使用它的开发人员但愿可使用相同的架构与非关系数据库交互。EF7 将为此提供较高级别的支持,可是请记住较高级别的真正含义。关系数据库和非关系数据库之间有极大的差别,但 EF 并不会尝试掩盖这些差别。但对于基本查询和更新,您可使用您已经熟悉的模式。
图 1 显示来自针对 Microsoft Azure Table Storage(一种非关系文档数据库)的示例应用的代码。该示例来自 EF 项目经理 Rowan Miller,您能够访问 github.com/rowanmiller/Demo-EF7,了解详细信息。请注意,该示例可针对 EF7 Alpha 每夜构建版本的 11514 版本运行。
图 1 为使用 Azure Table Storage 定义的 DbContext
public class WarrantyContext : DbContext { public DbSet<WarrantyInfo> Warranties { get; set; } protected override void OnConfiguring(DbContextOptions options) { var connection = ConfigurationManager.ConnectionStrings["WarrantyConnection"] .ConnectionString; options.UseAzureTableStorage(connection); } protected override void OnModelCreating(ModelBuilder builder) { builder.Entity<WarrantyInfo>() .ForAzureTableStorage() .PartitionAndRowKey(w => w.BikeModelNo, w => w.BikeSerialNo); } }
OnConfiguring 方法是新方法。该方法可影响 EF 如何在运行时配置 DbContext,相似于您如今能够对 DbConfiguration 类执行的操做。请注意 builder.UseAzureTableStorage 扩展方法,存在该方法是由于我还在项目中安装了 EntityFramework.AzureTableStorage 包。
EF7 为其不一样的提供程序使用此模式。如下是针对 SQLite 的项目中 DbContext 类中的 OnConfiguring 方法:
protected override void OnConfiguring(DbContextOptions builder) { string dir = ApplicationData.Current.LocalFolder.Path; string connection = "Filename=" + Path.Combine(dir, "VermontBrewery.db"); builder.UseSQLite(connection); }
此项目已安装了 EntityFramework.SQLite 包,所以如今我改成拥有 UseSQLite 扩展方法。
回到图 1 中的 WarrantyContext 类,您能够看到熟悉的 OnModelCreating 替代了 DbContext,而且我在其中进行了一些特殊的映射。一样,我拥有 EntityFramework.AzureTableStorage NuGet 包提供的方法。我要基于我须要的功能选择包。Azure Table Storage 依赖于键值对进行惟一标识以及支持表分区。为了检索或存储数据,知道为 PartitionKey 和 RowKey 使用什么值很关键,所以 API 提供一个方法 PartitionAndRowKey,该方法能够用于将属性映射到适当的键。这一律念无异于您能够如何使用 Fluent API 或数据注释来指定映射到关系数据库主键的属性。
因为此映射功能,我能够编写熟悉的 LINQ 查询来检索一些数据:
var warranty = _context.Warranties .Where(w => w.BikeModelNo == modelNo && w.BikeSerialNo == serialNo) .SingleOrDefault();
所以您看到的是一个典型的 LINQ 查询,但它是针对 Azure Table Storage 数据存储执行的,就像您如今能够对关系数据库执行的操做同样。
这一相同演示还能够更新保证对象;使用 DbSet.Add 建立和插入新的对象;使用 DbContext.SaveChanges 将全部内容保留到数据存储,就像如今使用 EF6 执行的操做以及在整个 EF 历史中执行过的操做同样。
此外,要考虑的比较有趣的一点是,实体框架如何始终支持映射到关系数据库的规范功能集,但由数据库提供程序指定这些功能集如何转换为其针对的数据库。EF7 将包含可被关系数据存储和非关系数据存储理解的高级规范功能集。还有专一于关系数据库的低级功能集,其密封在 EntityFramework.Relational 程序集中。全部关系数据库提供程序将依赖于这些功能,而且像如今同样,它们对数据库交互的特定处理将在其本身的提供程序 API(例如我以前使用的 EntityFramework.SQLite)中进行。您将在衍生 AsRelational 方法(位于关系 API 中)的提供程序中找到扩展方法。它是 DbContext 的扩展方法。
甚至还有一个内存中数据存储提供程序,可用于在您想要避免数据库交互(在您测试的逻辑中可能涉及到)时进行单元测试。在这些状况中,您一般可使用虚设或模拟框架来模拟数据库交互。
若是您要设置一个测试来执行查询或更新数据库,则最好使用一些代码来实例化数据库,例如:
using (var context = new BreweryContext()) { // Perform some action against the context }
经过先向测试项目中安装 entityframework.InMemory 包,为 InMemoryStore 定义 DbContextOption,而后指定上下文应使用该选项,您能够轻松地切换到内存中存储。一样,这多是由于此 API 提供了扩展方法:
var options = new DbContextOptions().UseInMemoryStore(); using (var context = new BreweryContext(options)){ // Perform some action against the context }
您能够在扩展方法提供的灵活性以及经过 OnConfiguring 重载影响实体框架管道的能力方面看到新代码库的优点。在整个新代码库中有扩展点,这些扩展点不只用于更改 EF7,还可让您更容易地将本身的逻辑插入到 EF7。
经过新的核心代码库,EF 团队能够解决一些老问题。例如,我使用的版本已支持批量更新,这是关系数据库的默认设置。我已使用容许我在 LINQ 查询中内嵌使用我本身的方法的代码,而不会收到使人讨厌的“实体框架没法将此方法转化为 SQL”的消息。相反,EF 和提供程序能够解析查询的哪一个部分将变成 SQL,哪一个部分将在客户端本地运行。我相信确定会有相应的保护和指导,以免有关该特定功能的一些潜在的性能问题。
团队能够为模型添加长久请求的惟一外键功能。他们也在仔细研究如何提供对表值函数的支持以及处理断开链接数据的更干净的方法,这是我多年以来一直关注实体框架的一点。这是断开链接应用程序的常见问题,并不是仅当涉及到实体框架时才有,而且很难建立在每种方案中均可以一致运行的算法。所以,确实须要一种新方法。
EF7 有不少使人兴奋的新功能。我强烈建议您仔细阅读 ADO.NET 团队博客 (blogs.msdn.com/adonet) 上的博文。除了我以前连接的博文,Rowan Miller 还深度讨论了有关在 EF7 中放弃支持设计器的决定;请参阅《EF7 -“代码优先”的实际意义》(bit.ly/1sLM3Ur)。请关注该博客以及 GitHub 项目。GitHub (bit.ly/1viwqXu) 上的 wiki 包含指向如何访问每夜构建版本、如何下载、编译和调试源代码以及一些演练和设计会议记录的连接。团队但愿获得您的反馈,对可以收到 Pull 请求感到很是高兴。
对我而言,撰写有关 EF7 的文章很重要,由于这有助于缓解有关这一巨大变革以及 EF7 中再也不提供对您的应用程序来讲不可或缺的一部分现有 EF 功能所带来的恐惧心理。这些恐惧并不是空穴来风,而团队和我都会谨慎对待。可是 EF6 并不会离咱们而去,而是将在社区的帮助之下继续完善,了解这一点很重要。若是您要利用这一发展,则要做出一些艰难的选择。升级大型应用程序并不是易事,您必须仔细权衡相关选择。或许您能够分解应用程序,仅从新编写其中一部分以便从 EF7 中受益。
一样,当我撰写此专栏时,EF7 仍处于其早期阶段,我不肯定当您阅读本文时 EF7 进展如何。但您能够就当前可用的源代码和 NuGet 包进行探索、实验并提供反馈。请记住,团队在完善核心 API 时可能不会一直保持全部提供程序 API(例如 Redis、SQLite 等)最新。根据 bit.ly/1ykagF0 上的博文《EF7 - 优先级、关注和首次发布》,首版 EF7 将关注与 ASP.NET 5 的兼容性。后续版本将添加更多功能。尽管 EF7 还没有足够稳定到能够用来构建应用程序,可是足以让您开始提早进行规划。
Julie Lerman是 Microsoft MVP、.NET 导师和顾问,住在佛蒙特州的山区。您能够在全球的用户组和会议中看到她对数据访问和其余 .NET 主题的演示。她是《Programming Entity Framework》(2010) 以及“代码优先”版 (2011) 和 DbContext 版 (2012)(均出自 O’Reilly Media)的做者,博客网址为thedatafarm.com/blog。经过她的 Twitter(网址为 twitter.com/julielerman)关注她,并在 juliel.me/PS-Videos 上观看其 Pluralsight 课程。
衷心感谢如下 Microsoft 技术专家对本文的审阅:Rowan Miller
本文基于 Entity Framework 7 的 Alpha 版本。文中的全部信息均有可能发生变动。