博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.Net Core 2.0生态(4):Entity Framework Core 2.0 特性介绍和使用指南
阅读量:5135 次
发布时间:2019-06-13

本文共 6901 字,大约阅读时间需要 23 分钟。

前言

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

对于.NET Core 2.0的发布介绍,围绕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.Customerswhere 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
    () .OwnsOne(c => c.Address);
  • 全局查询过滤器:在DbContext中为实体定义查询过滤器,下面代码在OnModelCreating方法中定义:

    modelBuilder.Entity
    () .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
    ( 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
() .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访问。

事件现在使用与对应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
().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 现在只需要引用单一的包

下一步计划

已经在进行下一个版本的开发,,另外也在完成。

遗憾的地方

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

转载于:https://www.cnblogs.com/YGYH/p/7416275.html

你可能感兴趣的文章
SNF快速开发平台MVC-EasyQuery-拖拽生成SQL脚本
查看>>
DrawerLayout实现双向侧滑
查看>>
MySQL入门很简单-触发器
查看>>
LVM快照(snapshot)备份
查看>>
绝望的第四周作业
查看>>
一月流水账
查看>>
数论四大定理
查看>>
npm 常用指令
查看>>
20几个正则常用正则表达式
查看>>
TextArea中定位光标位置
查看>>
非常棒的Visual Studo调试插件:OzCode 2.0 下载地址
查看>>
判断字符串在字符串中
查看>>
hdu4374One hundred layer (DP+单调队列)
查看>>
类间关系总结
查看>>
properties配置文件读写,追加
查看>>
Linux环境下MySql安装和常见问题的解决
查看>>
lrzsz——一款好用的文件互传工具
查看>>
ZPL语言完成条形码的打印
查看>>
这20件事千万不要对自己做!
查看>>
Linux环境下Redis安装和常见问题的解决
查看>>