EF Core 2.1 中的新增功能New features in EF Core 2.1

除了大量缺陷修复以及小规模功能增强和性能增强之外,EF Core 2.1 还新增了一些有吸引力的功能:

延迟加载Lazy loading

EF Core 现包含创作可按需加载导航属性的实体类所必需的构建基块。 我们还创建了一个新包 - Microsoft.EntityFrameworkCore.Proxies,它可利用这些构建基块基于最小修改实体类(例如具有虚拟导航属性的类)来生成延迟加载代理类。

阅读有关延迟加载的部分详细了解本主题。

实体构造函数中的参数Parameters in entity constructors

作为延迟加载所必需的一个构建基块,我们启用了实体创建,实体可将参数纳入其构造函数中。 可使用参数来注入属性值、延迟加载委托和服务。

阅读有关含参数的实体构造函数部分详细了解本主题。

值转换Value conversions

到目前为止,EF Core 只能映射底层数据库提供程序本机支持的属性类型。 在列和属性之间来回复制值,无需进行任何转换。 自 EF Core 2.1 起,可通过值转换来转换从列获取的值,之后再将其应用到属性,反之亦然。 我们具有可以根据约定按需应用的大量转换,以及显式配置 API,后者允许在列和属性之间注册自定义转换。 此功能有如下一些用法:

  • 将枚举存储为字符串
  • 使用 SQL Server 映射无符号整数
  • 自动加密和解密属性值

阅读有关值转换的部分详细了解本主题。

LINQ GroupBy 转换LINQ GroupBy translation

在 2.1 版之前,EF Core 中的 GroupBy LINQ 运算符将始终在内存中进行计算。 在大多数情况下,我们现在支持将其转换为 SQL GROUP BY 子句。

此示例显示了一个用 GroupBy 来计算各种聚合函数的查询:

  1. var query = context.Orders
  2. .GroupBy(o => new { o.CustomerId, o.EmployeeId })
  3. .Select(g => new
  4. {
  5. g.Key.CustomerId,
  6. g.Key.EmployeeId,
  7. Sum = g.Sum(o => o.Amount),
  8. Min = g.Min(o => o.Amount),
  9. Max = g.Max(o => o.Amount),
  10. Avg = g.Average(o => o.Amount)
  11. });

相应的 SQL 转化如下所示:

  1. SELECT [o].[CustomerId], [o].[EmployeeId],
  2. SUM([o].[Amount]), MIN([o].[Amount]), MAX([o].[Amount]), AVG([o].[Amount])
  3. FROM [Orders] AS [o]
  4. GROUP BY [o].[CustomerId], [o].[EmployeeId];

数据种子设定Data Seeding

新版本可提供初始数据来填充数据库。 与 EF6 不同,种子设定数据作为模型配置的一部分与实体类型相关联。 随后将数据库升级为新版本模型时,EF Core 迁移会自动计算需要应用的插入、更新或删除操作。

如示例所示,可使用它在 OnModelCreating 中为 Post 配置种子数据:

  1. modelBuilder.Entity<Post>().HasData(new Post{ Id = 1, Text = "Hello World!" });

阅读有关数据种子设定的部分详细了解本主题。

查询类型Query types

EF Core 模型现可包含查询类型。 与实体类型不同,查询类型上未定义键,也不能插入、删除或更新查询类型(即它们为只读),但查询可直接返回查询类型。 以下是查询类型的一些用法:

  • 映射到没有主键的视图
  • 映射到没有主键的表
  • 映射到模型中定义的查询
  • 用作 FromSql() 查询的返回类型

阅读有关查询类型的部分详细了解本主题。

针对派生类型的 IncludeInclude for derived types

现可在编写 Include 方法的表达式时指定仅在派生类型上定义的导航属性。 对于 Include 的强类型版本,我们支持使用显式强制转换或 as 运算符。 我们现在还支持在 Include 的字符串版本中引用在派生类型上定义的导航属性的名称:

  1. var option1 = context.People.Include(p => ((Student)p).School);
  2. var option2 = context.People.Include(p => (p as Student).School);
  3. var option3 = context.People.Include("School");

阅读有关派生类型的 Include 部分详细了解本主题。

System.Transactions 支持System.Transactions support

我们增加了对 System.Transactions 功能(如 TransactionScope)的应用。 使用支持该功能的数据库提供程序时,这将适用于 .NET Framework 和 .NET Core。

阅读有关 System.Transactions 的部分详细了解本主题。

初始迁移时生成更好的列顺序Better column ordering in initial migration

根据客户反馈,我们对迁移进行了更新,使得先以与类中声明的属性相同的顺序为表生成列。 请注意,在创建初始表后,添加新成员时,EF Core 不能更改顺序。

相关子查询优化Optimization of correlated subqueries

我们改进了查询转换,避免在许多常见情况下执行“N + 1”SQL 查询,一般情况下,在投影中使用导航属性后,来自根查询的数据会与来自相关子查询的数据相连接。 进行优化需要缓冲子查询的结果,且我们要求修改查询,选择新行为。

例如,以下查询通常会转换为:一个“客户”查询,加上 N(其中“N”是返回的客户数量)个单独的“订单”查询:

  1. var query = context.Customers.Select(
  2. c => c.Orders.Where(o => o.Amount > 100).Select(o => o.Amount));

ToList() 放入正确的位置,指示缓冲适用于订单,即可启用优化:

  1. var query = context.Customers.Select(
  2. c => c.Orders.Where(o => o.Amount > 100).Select(o => o.Amount).ToList());

请注意,此查询只会被转换为两个 SQL 查询:一个“客户”查询,一个“订单”查询。

[Owned] 属性[Owned] attribute

现只需使用 [Owned] 注释类型,并确保所有者实体添加到了模型中,即可配置固有实体类型

  1. [Owned]
  2. public class StreetAddress
  3. {
  4. public string Street { get; set; }
  5. public string City { get; set; }
  6. }
  7. public class Order
  8. {
  9. public int Id { get; set; }
  10. public StreetAddress ShippingAddress { get; set; }
  11. }

.NET Core SDK 中包含的命令行工具 dotnet-efCommand-line tool dotnet-ef included in .NET Core SDK

dotnet-ef 命令现在是 .NET Core SDK 的一部分,因此无须在项目中使用 DotNetCliToolReference 即可使用各项迁移,或通过现有数据库搭建 DbContext 基架 。

有关如何为不同版本的 .NET Core SDK 和 EF Core 启用命令行工具的详细信息,请参阅安装工具的相关部分。

Microsoft.EntityFrameworkCore.Abstractions 包Microsoft.EntityFrameworkCore.Abstractions package

可以在项目中使用新包内的一些属性和接口,从而启用 EF Core 功能,而无需依赖 EF Core 整体。 例如,[Owned] 属性和 ILazyLoader 接口位于此处。

状态更改事件State change events

ChangeTracker 中新增的 TrackedStateChanged 事件可用于编写逻辑,以响应进入 DbContext 或状态更改的实体。

原始 SQL 参数分析器Raw SQL parameter analyzer

EF Core 随附新增一个代码分析器,用于检测原始 SQL API(如 FromSqlExecuteSqlCommand)的潜在不安全用法。 例如,对于下面的查询,将会看到一条警告,因为 minAge 未参数化 :

  1. var sql = $"SELECT * FROM People WHERE Age > {minAge}";
  2. var query = context.People.FromSql(sql);

数据库提供程序兼容性Database provider compatibility

建议配合使用 EF Core 2.1 以及已更新或至少已经过测试可用于 EF Core 2.1 的提供程序。

提示

如果新功能出现任何意外的不兼容或问题,或你有任何相关反馈,请使用我们的问题跟踪器进行报告。