这是.Net Core 2.0生态生态介绍的最后一篇,EF一直是我喜欢的一个ORM框架,随着版本升级EF也发展到EF6.x,Entity Framework Core是一个支持跨平台的全新版本,能够用三个词来概况EF Core的特色:轻量级、可扩展、跨平台。跨平台的特性是EF6.x没法替代的优点,也许会成为你在项目中技术选型的缘由之一。html
对于.NET Core 2.0的发布介绍,围绕2.0的架构体系,本系列相关文章:git
在命令行工具安装NuGet包,好比:安装SQL Server EF Core提供程序,并指定版本为2.0.0
。github
$ dotnet add package Microsoft.EntityFrameworkCore.SqlServer -V 2.0.0
在VS2017中使用包管理器控制台安装sql
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指南,查看更多安装和升级细节,进入帮助文档。api
如下是最显著的新特性:架构
使用.NET Standard 2.0目标框架:这使得EF Core 2.0可支持多种.NET平台实现和应用程序类型,查看平台支持列表。app
LINQ解析改进:EF Core 2.0中的查询更加高效,适应多种场景。举个例子,增长了翻译成SQL语句模式的数量限制,避免了在之前版本中由于客户端计算致使多重查询的问题。(优化了客户端计算性能)框架
Like查询支持:LINQ查询可使用EF.Functions.Like()
,最终解析为SQL中的like
语句,在必要的时候会进行内存计算,举个例子,下面的查询:less
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。详细内容参考:新功能
在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设计时支持,不推荐这么作。
为了支持不一样的应用模式,在设计时提供对DbContext
更多自定义控制,在之前的版本提供接口IDbContextFactory<TContext>
,EF Core工具在设计时,会发现应用程序中该接口的实现并使用它来建立DbContext
对象。
这个接口由于具备通用性的名称,容易误导开发者使用来处理须要从新建立DbContext
的开发场景,当在设计时EF Core工具使用它时由于没有考虑到设计时的特殊环境能够致使Update-Database
或dotnet ef database update
命令执行失败。
基于以上的缘由,为了更精准的表达该接口的做用,咱们将其更名为IDesignTimeDbContextFactory<TContext>
,在2.0中IDbContextFactory<TContext>
仍然存在,可是已经标记为过期了。
由于ASP.NET 2.0的升级,咱们发如今接口IDesignTimeDbContextFactory<TContext>
不在须要DbContextFactoryOptions
。
下面是你应该使用的替代方案。
对于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 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 Core使用内置IServiceProvider
在框架内部实现,应用程序应该容许EF Core建立和管理这个提供程序。强烈建议删除全部UseInternalServiceProvider
的调用,AddEntityFramework
,AddEntityFrameworkSqlServer
不须要经过应用程序代码调用,建议移除。AddDbContext
的使用方式和之前同样。
全局匿名内存数据库已经被删除,而全部内存数据库都必须被命名。
optionsBuilder.UseInMemoryDatabase("MyDatabase");
名称相同就算调用屡次,仍然使用同一个数据库,容许由多个上下文实例共享。
IsReadOnlyBeforeSave
, IsReadOnlyAferSave
, 和 IsStoreGeneratedAlways
已通过时,由 BeforeSaveBehavior
和 AfterSaveBehavior
代替。这些行为应用到任何属性(不只是存储生成的属性)并检测属性值如何被使用,好比插入数据库行(BeforeSaveBehavior)或更新现有数据库行(AfterSaveBehavior)。
属性经过ValueGenerated.OnAddOrUpdate
进行标记,例如:计算列。默认状况下,将忽略当前设置在该属性上的任何值。这意味着不管是否在跟踪实体上设置或修改了任何值,都将始终得到一个存储生成的值。这能够经过设置不一样的Before\AfterSaveBehavior
来改变。
在之前的版本中DeleteBehavior.Restrict
经过上下文对实体有一个跟踪行为,这些实体与SetNull语义更加封闭。在EF Core 2.0中一个新的行为ClientSetNull
做为可选关系的默认值。此行为为跟踪实体设置了SetNull语义,并限制使用EF Core建立的数据库的行为。根据咱们的经验这对跟踪实体和数据库是很是有用的。
Microsoft.EntityFrameworkCore.Relational.Design
引用包移除,功能被整合进Microsoft.EntityFrameworkCore.Relational
和 Microsoft.EntityFrameworkCore.Design
引用包。
不一样数据设计时引用包,好比Microsoft.EntityFrameworkCore.Sqlite.Design
, Microsoft.EntityFrameworkCore.SqlServer.Design
,整合进其主提供程序中。
在EF Core 2.0中启用Scaffold-DbContext
或 dotnet 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。