前言

这是.Net Core 2.0生态生态介绍的最后一篇,EF一直是我喜欢的一个ORM框架,随着版本升级EF也发展到EF6.x,Entity Framework Core是一个支持跨平台的全新版本,可以用三个词来概况EF Core的特点:轻量级、可扩展、跨平台。跨平台的特性是EF6.x无法替代的优势,也许会成为你在项目中技术选型的原因之一。

对于.NET Core 2.0的发布介绍,围绕2.0的架构体系,本系列相关文章:

  1. .Net Core 2.0 生态(1).NET Standard 2.0 特性介绍和使用指南(已发布)
  2. .Net Core 2.0 生态(2).NET Core 2.0 特性介绍和使用指南(已发布)
  3. .Net Core 2.0 生态(3)ASP.NET Core 2.0 特性介绍和使用指南(已发布)
  4. .Net Core 2.0 生态(4)Entity Framework Core 2.0 特性介绍和使用指南(已发布)

获取和使用

在命令行工具安装NuGet包,比如:安装SQL Server EF Core提供程序,并指定版本为2.0.0

$ dotnet add package Microsoft.EntityFrameworkCore.SqlServer -V 2.0.0

在VS2017中使用包管理器控制台安装

PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 2.0.0

在ASP.NET Core 2.0默认项目包含支持EF Core 2.0的SQL Server, SQLite, 和 in-memory数据库提供程序,创建项目无需额外添加。

查看在不同平台上使用EF Core指南,查看更多安装和升级细节,进入帮助文档

新特性

以下是最显著的新特性:

  • 使用.NET Standard 2.0目标框架:这使得EF Core 2.0可支持多种.NET平台实现和应用程序类型,查看平台支持列表

  • LINQ解析改进:EF Core 2.0中的查询更加高效,适应多种场景。举个例子,增加了翻译成SQL语句模式的数量限制,避免了在以前版本中因为客户端计算导致多重查询的问题。(优化了客户端计算性能)

  • Like查询支持:LINQ查询可以使用EF.Functions.Like(),最终解析为SQL中的like语句,在必要的时候会进行内存计算,举个例子,下面的查询:

    var customers =
    from c in context.Customers
    where EF.Functions.Like(c.Name, "a%");
    select c;

    解析成SQL语句:

    SELECT [c].[Id], [c].[Name]
    FROM [Customers] AS [c]
    WHERE [c].[Name] LIKE N'a%';

    和SQL中like语句一样使用通配符。

  • 实体包含关系和表拆分:可以通过属性关联建立实体之间的包含关系,这个特性和EF6中的复合类型类似,只需要定义一个导航属性。实体包含关系定义与表拆分结合使用,可以将两个实体自动映射为单张表,参看下面的示例:

      public class Customer
    {
    public int Id { get; set; }
    public string Name {get; set;}
    public PhysicalAddress Address { get; set; }
    } public class PhysicalAddress
    {
    public string StreetAddress { get; set; }
    public Location Location { get; set; }
    } ... modelBuilder.Entity<Customer>()
    .OwnsOne(c => c.Address);
  • 全局查询过滤器:在DbContext中为实体定义查询过滤器,下面代码在OnModelCreating方法中定义:

      modelBuilder.Entity<Post>()
    .HasQueryFilter(p => !p.IsDeleted);

    下面的查询只会返回未被标记为删除的结果:

    var blog = context.Blogs
    .Include(b => b.Posts)
    .FirstOrDefault(b => b.Id == id);

    这个特性在特殊的业务场景下将有大用处,比如多租户中数据过滤实现。

  • DbContext Pooling(池):这项特性能够显著提升Asp.net Core应用程序的性能,通过在服务注册DbContext类型时启用,使用预先创建的实例池,避免为每个请求创建新实例:

    services.AddDbContextPool<BloggingContext>(
    options => options.UseSqlServer(connectionString));

    这是一个最佳实践,推荐使用!

  • SQL方法支持字符串插值:下面的SQL语句使用了C#中字符串插值语法,简化参数化查询:

      var city = "Redmond";
    
      using (var context = CreateContext())
    {
    context.Customers.FromSql($@"
    SELECT *
    FROM Customers
    WHERE City = {city}");
    }

    以上代码转换为SQL语句会创建一个名为@p0的参数,值为Redmond,生成如下SQL语句:

      SELECT *
    FROM Customers
    WHERE City = @p0
  • 更多特性:如:显式编译查询、自包含实体配置、数据库标准函数映射。还修复了许多Bug。详细内容参考:新功能

项目升级和核心API变化

  1. 将项目.NET平台设置为支持.NET Standard 2.0的平台
  2. 使用支持2.0的数据库提供程序
  3. 更新EF Core引用包(包括运行时和工具)到2.0
  4. 必要的时候对代码进行修改,具体参看核心变化

在2.0版本中,部分API和操作有较大改进,有部分改进需要修改现有程序代码,对于大多数应用程序来说,影响不大,大多数情况下,只需要重新编译和最少的修改来替换过时的API。

获取应用程序服务新方式

注:EF Core在设计时的操作比如生成数据迁移代码,更新数据库,需要访问应用程序服务。设计时工具和应用程序存在调用关系。

推荐将ASP.NET Core Web应用程序更新到2.0,在ASP.NET Core 2.0在启动类之外初始化配置。在之前的版本EF Core尝试执行Startup.ConfigureServices,直接访问应用程序的服务提供者,使用EF Core的应用程序通常从配置文件中访问连接字符串,所以单靠Startup已经不能满足获取连接字符串的需要。

更新ASP.NET Core 1.x到2.0,当使用了EF Core工具,会收到如下错误提示:

No parameterless constructor was found on 'ApplicationContext'. Either add a parameterless constructor to 'ApplicationContext' or add an implementation of 'IDesignTimeDbContextFactory' in the same assembly as 'ApplicationContext'

在ASP.NET Core 2.0默认模板中新增设计时支持,静态方法Program.BuildWebHost允许EF Core在设计时访问应用程序服务提供者,如果升级ASP.NET Core 1.x应用程序,同时升级Program

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; namespace AspNetCoreDotNetCore2._0App
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
} public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}

注:如果没有ASP.NET Core 2.0应用程序没有更改Program启动方式,依然可以使用实现IDesignTimeDbContextFactory<ApplicationContext>接口方式提供EF Core 2.0设计时支持,不推荐这么做。

IDbContextFactory改名

为了支持不同的应用模式,在设计时提供对DbContext更多自定义控制,在以前的版本提供接口IDbContextFactory<TContext>,EF Core工具在设计时,会发现应用程序中该接口的实现并使用它来创建DbContext对象。

这个接口因为具有通用性的名称,容易误导开发者使用来处理需要重新创建DbContext的开发场景,当在设计时EF Core工具使用它时因为没有考虑到设计时的特殊环境可以导致Update-Databasedotnet ef database update命令执行失败。

基于以上的原因,为了更精准的表达该接口的作用,我们将其改名为IDesignTimeDbContextFactory<TContext>,在2.0中IDbContextFactory<TContext>仍然存在,但是已经标记为过时了。

DbContextFactoryOptions移除

因为ASP.NET 2.0的升级,我们发现在接口IDesignTimeDbContextFactory<TContext>不在需要DbContextFactoryOptions

下面是你应该使用的替代方案。

  • DbContextFactoryOptions.ApplicationBasePath 使用AppContext.BaseDirectory代替
  • DbContextFactoryOptions.ContentRootPath 使用Directory.GetCurrentDirectory()代替
  • DbContextFactoryOptions.EnvironmentName 使用Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")代替

EF Core 2.0需要2.0数据库提供程序

对于EF Core 2.0,我们已经对数据库提供程序的工作进行了许多简化和改进。1.0.x和1.1.x提供程序已经不能在EF Core 2.0下工作。

由EF团队开发的SQL Server和SQLite数据库提供程序,2.0版本将在2.0版本中提供。其他数据库提供程序也已经升级到2.0版本:

日志记录和诊断事件更改

注意:这些更改不会影响大多数的应用程序代码。

发送给ILogger的消息的事件ID在2.0中发生了变化。现在在EF Core中事件ID是全局唯一的。这些消息现在也遵循了结构化日志的标准模式,例如,MVC。

Logger类别也发生了变化,类别可通过DbLoggerCategory访问。

DiagnosticSource事件现在使用与对应ILogger消息相同的时间ID名称,事件ID、有效负载类型和类别进行了统一。

ID从Microsoft.EntityFrameworkCore.Infraestructure命名空间移到Microsoft.EntityFrameworkCore.Diagnostics

EF Core元数据关系API变化

EF Core 2.0为不同的提供程序创建一个不同的IModel,这通常对应用程序是透明的,从而简化了底层元数据API,使得任何对公共关系的元数据都可以通过调用来实现,对比如下代码,在1.1.x中代码:

var tableName = context.Model.FindEntityType(typeof(User)).SqlServer().TableName;

现在可以这么写

var tableName = context.Model.FindEntityType(typeof(User)).Relational().TableName;

更具通用性。

在比如使用方法ForSqlServerToTable,现在可以使用更加通用的代码来实现

modelBuilder.Entity<User>().ToTable(
Database.IsSqlServer() ? "SqlServerName" : "OtherName");

请注意,此更改仅适用于为所有关系提供程序定义的API/元数据。当只针对单个提供者时,API和元数据仍然是相同的。举个例子,聚集索引是SQL Server特有的,所以ForSqlServerIsClustered.SqlServer().IsClustered()必须使用。

不要控制EF服务提供程序

EF Core使用内置IServiceProvider在框架内部实现,应用程序应该允许EF Core创建和管理这个提供程序。强烈建议删除所有UseInternalServiceProvider的调用,AddEntityFrameworkAddEntityFrameworkSqlServer不需要通过应用程序代码调用,建议移除。AddDbContext的使用方式和以前一样。

内存数据库必须命名

全局匿名内存数据库已经被删除,而所有内存数据库都必须被命名。

optionsBuilder.UseInMemoryDatabase("MyDatabase");

名称相同就算调用多次,仍然使用同一个数据库,允许由多个上下文实例共享。

Read-only API 变化

IsReadOnlyBeforeSave, IsReadOnlyAferSave, 和 IsStoreGeneratedAlways 已经过时,由 BeforeSaveBehaviorAfterSaveBehavior代替。这些行为应用到任何属性(不仅是存储生成的属性)并检测属性值如何被使用,比如插入数据库行(BeforeSaveBehavior)或更新现有数据库行(AfterSaveBehavior)。

属性通过ValueGenerated.OnAddOrUpdate进行标记,例如:计算列。默认情况下,将忽略当前设置在该属性上的任何值。这意味着无论是否在跟踪实体上设置或修改了任何值,都将始终获得一个存储生成的值。这可以通过设置不同的Before\AfterSaveBehavior来改变。

新的ClientSetNull删除行为

在以前的版本中DeleteBehavior.Restrict通过上下文对实体有一个跟踪行为,这些实体与SetNull语义更加封闭。在EF Core 2.0中一个新的行为ClientSetNull作为可选关系的默认值。此行为为跟踪实体设置了SetNull语义,并限制使用EF Core创建的数据库的行为。根据我们的经验这对跟踪实体和数据库是非常有用的。

设计时提供程序更改

Microsoft.EntityFrameworkCore.Relational.Design引用包移除,功能被整合进Microsoft.EntityFrameworkCore.RelationalMicrosoft.EntityFrameworkCore.Design引用包。

不同数据设计时引用包,比如Microsoft.EntityFrameworkCore.Sqlite.Design, Microsoft.EntityFrameworkCore.SqlServer.Design,整合进其主提供程序中。

在EF Core 2.0中启用Scaffold-DbContextdotnet ef dbcontext scaffold 现在只需要引用单一的包

<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer"
Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools"
Version="2.0.0"
PrivateAssets="All" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet"
Version="2.0.0" />

下一步计划

已经在进行下一个版本的开发,查看开发计划,另外也在完成EF 6.2

遗憾的地方

  • 不支持GroupBy、延迟加载——这两个特性都在2.1计划中

.Net Core 2.0生态(4):Entity Framework Core 2.0 特性介绍和使用指南的更多相关文章

  1. Professional C# 6 and .NET Core 1.0 - Chapter 38 Entity Framework Core

    本文内容为转载,重新排版以供学习研究.如有侵权,请联系作者删除. 转载请注明本文出处:Professional C# 6 and .NET Core 1.0 - Chapter 38 Entity F ...

  2. ASP.NET CORE系列【六】Entity Framework Core 之数据迁移

    原文:ASP.NET CORE系列[六]Entity Framework Core 之数据迁移 前言 最近打算用.NET Core写一份简单的后台系统,来练练手 然后又用到了Entity Framew ...

  3. ASP.NET CORE系列【六】Entity Framework Core 之数据库迁移

    前言 最近打算用.NET Core写一份简单的后台系统,来练练手 然后又用到了Entity Framework Core 发现园子里有些文章讲得不是那么细节,对于新手小白来说,可能会有点懵. 特意整理 ...

  4. Entity Framework Core系列之什么是Entity Framework Core

    前言 Entity Framework Core (EF Core)是微软推荐的基于.NET Core framework的应用程序数据访问技术.它是轻量级,可扩展并且支持跨平台开发.EF Core是 ...

  5. Professional C# 6 and .NET Core 1.0 - 38 Entity Framework Core

    本文内容为转载,重新排版以供学习研究.如有侵权,请联系作者删除. 转载请注明本文出处:Professional C# 6 and .NET Core 1.0 - 38 Entity Framework ...

  6. Entity Framework Core 2.0 全局查询过滤器

    不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: http://gunnarpeipman.com/2017/08/ef ...

  7. ASP.NET Core 中的 ORM 之 Entity Framework

    目录 EF Core 简介 使用 EF Core(Code First) EF Core 中的一些常用知识点 实体建模 实体关系 种子数据 并发管理 执行 SQL 语句和存储过程 延迟加载和预先加载 ...

  8. Working with Data » Getting started with ASP.NET Core and Entity Framework Core using Visual Studio » 排序、筛选、分页以及分组

    Sorting, filtering, paging, and grouping 7 of 8 people found this helpful By Tom Dykstra The Contoso ...

  9. 浅析Entity Framework Core中的并发处理

    前言 Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章.. 本文主要是浅析一下Entity Framework Core的并发处理方式. 1.常见的并发处 ...

  10. Entity Framework Core 入门(2)

    安装 EF Core 将 EF Core 添加到不同平台和常用 IDE 中的应用程序的所需步骤汇总. 分步入门教程 无需具备 Entity Framework Core 或任何特定 IDE 的原有知识 ...

随机推荐

  1. 给xcode项目修改名字

    在xcode项目开发中,经常会遇到需要修改项目名字的问题, 但是xcode本身修改项目名字比较麻烦,有时候修改的不完全,有时候修改了项目无法打开,无奈只能建一个新项目.这里提供一种修改xcode项目名 ...

  2. 英文版windows7中文软件显示乱码的解决办法

    一.打开控制面板,修改语言的归属地为China 修改完成之后重启,一般能解决大部分问题,如果依然有部分显示乱码,就需要去修改注册表

  3. STL—vector

    前面介绍了STL对象的构造与析构以及内存的配置与释放,那具体的容器是怎么应用STL的空间配置器的呢?这篇先介绍STL的容器vector. vector的数据成员 vector只有4个数据成员:3个迭代 ...

  4. rsync技术报告(翻译)

    本篇为rsync官方推荐技术报告rsync technical report的翻译,主要内容是Rsync的算法原理以及rsync实现这些原理的方法.翻译过程中,在某些不易理解的地方加上了译者本人的注释 ...

  5. Java 9 揭秘(14. HTTP/2 Client API)

    Tips 做一个终身学习的人. 在此章中,主要介绍以下内容: 什么是HTTP/2 Client API 如何创建HTTP客户端 如何使HTTP请求 如何接收HTTP响应 如何创建WebSocket的e ...

  6. JSON的详细介绍

    JSON的语法可以表示以下三种类型的值: 简单值:可以表示字符串,数值,布尔值,null,但不支持undefined. 对象(Object):对象作为一种复杂数据类型,表示的是一组无序的键值对儿. 数 ...

  7. 移动端touch事件封装

    <meta charset="utf-8"><meta name="viewport" content="width=device- ...

  8. 文科生细谈学习Linux系统的重要性

    首先大概介绍下自己,我学的是公共事业管理方面的专业,可以说是面向纯理论,社区管理社会管理的专业,但是从大二开始,对网络及服务器运维方面产生浓厚兴趣,并不断在网上找相关资料. 在这期间经历过很多,单说桌 ...

  9. 云计算——Google App Eng…

    云计算--Google App Engine(一) 编者:王尚 2014.04.12 20:20 介绍:Google App Engine提供一套开发组件让用户轻松的在本地构建和调试网络应用,之后能让 ...

  10. ABP+AdminLTE+Bootstrap Table权限管理系统第七节--登录逻辑及abp封装的Javascript函数库

    经过前几节,我们已经解决数据库,模型,DTO,控制器和注入等问题.那么再来看一下登录逻辑.这里算是前面几节的一个初次试水. 首先我们数据库已经有的相应的数据. 模型和DTO已经建好,所以我们直接在服务 ...