這是.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。