EF Core 5.0 的新功能
下列清單包含EF Core 5.0的主要新功能。 如需發行中問題的完整清單,請參閱我們的 問題追蹤器。
作為主要版本,EF Core 5.0 也包含數 項重大變更,這些變更是 API 改進或行為變更,可能對現有應用程式造成負面影響。
多對多
EF Core 5.0 支援多對多關聯性,而不會明確對應聯結數據表。
例如,請考慮下列實體類型:
public class Post
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int Id { get; set; }
public string Text { get; set; }
public ICollection<Post> Posts { get; set; }
}
EF Core 5.0 會依照慣例將此辨識為多對多關聯性,並自動在資料庫中建立 PostTag
聯結數據表。 您可以查詢和更新數據,而不需明確參考聯結數據表,大幅簡化程序代碼。 如有需要,仍然可以自定義聯結數據表並明確查詢。
如需詳細資訊, 請參閱多對多的完整檔。
分割查詢
從EF Core 3.0 開始,EF Core 一律會為每個 LINQ 查詢產生單一 SQL 查詢。 這可確保在使用中交易模式的條件約束內傳回的數據一致性。 不過,當查詢使用 Include
或投影來傳回多個相關集合時,這可能會變得非常緩慢。
EF Core 5.0 現在允許單一 LINQ 查詢,包括相關的集合分割成多個 SQL 查詢。 這可以大幅改善效能,但如果兩個查詢之間的數據變更,可能會導致傳回的結果不一致。 可串行化或快照集交易可用來減輕這種情況,並達到與分割查詢的一致性,但這可能會帶來其他效能成本和行為差異。
例如,請考慮使用 Include
來提取兩個相關集合層級的查詢:
var artists = context.Artists
.Include(e => e.Albums)
.ToList();
根據預設,EF Core 會在使用 SQLite 提供者時產生下列 SQL:
SELECT a."Id", a."Name", a0."Id", a0."ArtistId", a0."Title"
FROM "Artists" AS a
LEFT JOIN "Album" AS a0 ON a."Id" = a0."ArtistId"
ORDER BY a."Id", a0."Id"
使用分割查詢時,會改為產生下列 SQL:
SELECT a."Id", a."Name"
FROM "Artists" AS a
ORDER BY a."Id"
SELECT a0."Id", a0."ArtistId", a0."Title", a."Id"
FROM "Artists" AS a
INNER JOIN "Album" AS a0 ON a."Id" = a0."ArtistId"
ORDER BY a."Id"
您可以將新的 AsSplitQuery
運算子放在 LINQ 查詢中的任何位置,或全域放在模型的 OnConfiguring
中,以啟用分割查詢。 如需詳細資訊, 請參閱分割查詢的完整檔。
簡單的記錄和改良的診斷
EF Core 5.0 引進了透過新 LogTo
方法設定記錄的簡單方式。 下列作業會導致記錄訊息寫入主控台,包括EF Core 所產生的所有 SQL:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(Console.WriteLine);
此外,現在可以在任何 LINQ 查詢上呼叫 ToQueryString
,擷取查詢將執行的 SQL:
Console.WriteLine(
ctx.Artists
.Where(a => a.Name == "Pink Floyd")
.ToQueryString());
最後,各種EF Core 類型都安裝了增強 DebugView
屬性,可提供內部內部的詳細檢視。 例如, ChangeTracker.DebugView 您可以查閱以查看在指定時刻追蹤哪些實體。
如需詳細資訊, 請參閱記錄和攔截的檔。
篩選的 include
方法 Include
現在支援篩選包含的實體:
var blogs = context.Blogs
.Include(e => e.Posts.Where(p => p.Title.Contains("Cheese")))
.ToList();
此查詢會將部落格連同每個相關聯的文章一起傳回,但前提是文章標題包含 “Cheese”。
如需詳細資訊, 請參閱篩選包含的完整檔。
每一類型的數據表對應 (TPT) 對應
根據預設,EF Core 會將 .NET 類型的繼承階層對應至單一資料庫數據表。 這稱為數據表個別階層 (TPH) 對應。 EF Core 5.0 也允許將繼承階層中的每個 .NET 類型對應至不同的資料庫數據表;稱為數據表個別類型 (TPT) 對應。
例如,請考慮具有對應階層的此模型:
public class Animal
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Cat : Animal
{
public string EducationLevel { get; set; }
}
public class Dog : Animal
{
public string FavoriteToy { get; set; }
}
使用 TPT 時,會針對階層中的每個類型建立資料庫資料表:
CREATE TABLE [Animals] (
[Id] int NOT NULL IDENTITY,
[Name] nvarchar(max) NULL,
CONSTRAINT [PK_Animals] PRIMARY KEY ([Id])
);
CREATE TABLE [Cats] (
[Id] int NOT NULL,
[EducationLevel] nvarchar(max) NULL,
CONSTRAINT [PK_Cats] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Cats_Animals_Id] FOREIGN KEY ([Id]) REFERENCES [Animals] ([Id]) ON DELETE NO ACTION,
);
CREATE TABLE [Dogs] (
[Id] int NOT NULL,
[FavoriteToy] nvarchar(max) NULL,
CONSTRAINT [PK_Dogs] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Dogs_Animals_Id] FOREIGN KEY ([Id]) REFERENCES [Animals] ([Id]) ON DELETE NO ACTION,
);
如需詳細資訊, 請參閱 TPT 的完整檔。
彈性實體對應
實體類型通常會對應至數據表或檢視表,讓EF Core 在查詢該類型時會提取數據表或檢視表的內容。 EF Core 5.0 新增其他對應選項,其中實體可以對應至 SQL 查詢(稱為「定義查詢」),或數據表值函式 (TVF):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>().ToSqlQuery(
@"SELECT Id, Name, Category, BlogId FROM posts
UNION ALL
SELECT Id, Name, ""Legacy"", BlogId from legacy_posts");
modelBuilder.Entity<Blog>().ToFunction("BlogsReturningFunction");
}
數據表值函式也可以對應至 .NET 方法,而不是對應至 DbSet,允許傳遞參數;您可以使用 來設定 HasDbFunction對應。
最後,現在可以在查詢時將實體對應至檢視表(或函式或定義查詢),但在更新時對應至數據表:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Blog>()
.ToTable("Blogs")
.ToView("BlogsView");
}
共用類型實體類型和屬性包
EF Core 5.0 可讓相同的 CLR 類型對應至多個不同的實體類型;這類類型稱為共用類型實體類型。 雖然任何 CLR 類型都可以與此功能搭配使用,但 .NET Dictionary
提供一個特別吸引人的使用案例,我們稱之為「屬性包」:
public class ProductsContext : DbContext
{
public DbSet<Dictionary<string, object>> Products => Set<Dictionary<string, object>>("Product");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.SharedTypeEntity<Dictionary<string, object>>("Product", b =>
{
b.IndexerProperty<int>("Id");
b.IndexerProperty<string>("Name").IsRequired();
b.IndexerProperty<decimal>("Price");
});
}
}
然後,您可以查詢和更新這些實體,就像使用自己的專用 CLR 類型一般實體類型一樣。 如需詳細資訊,請參閱屬性包檔。
必要 1:1 相依專案
在 EF Core 3.1 中,一對一關聯性的相依端一律視為選擇性。 使用擁有的實體時,這是最明顯的,因為所有擁有實體的數據行都會在資料庫中建立為可為 Null,即使它們已在模型中設定為必要也一樣。
在EF Core 5.0 中,可以將瀏覽至擁有的實體設定為必要的相依專案。 例如:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>(b =>
{
b.OwnsOne(e => e.HomeAddress,
b =>
{
b.Property(e => e.City).IsRequired();
b.Property(e => e.Postcode).IsRequired();
});
b.Navigation(e => e.HomeAddress).IsRequired();
});
}
DbContextFactory
EF Core 5.0 引進 AddDbContextFactory
並 AddPooledDbContextFactory
註冊處理站,以在應用程式的相依性插入 (D.I.) 容器中建立 DbContext 實例;當應用程式程式代碼需要手動建立和處置內容實例時,這非常有用。
services.AddDbContextFactory<SomeDbContext>(b =>
b.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"));
此時,ASP.NET Core 控制器等應用程式服務可以插入 IDbContextFactory<TContext>
,並使用它來具現化內容實例:
public class MyController : Controller
{
private readonly IDbContextFactory<SomeDbContext> _contextFactory;
public MyController(IDbContextFactory<SomeDbContext> contextFactory)
=> _contextFactory = contextFactory;
public void DoSomeThing()
{
using (var context = _contextFactory.CreateDbContext())
{
// ...
}
}
}
如需詳細資訊, 請參閱 DbContextFactory 的完整檔。
SQLite 資料表重建
與其他資料庫相比,SQLite 在其架構操作功能中相對有限;例如,不支援從現有數據表卸除數據行。 EF Core 5.0 可藉由自動建立新數據表、從舊數據表複製數據、卸除舊數據表並重新命名新數據表,來解決這些限制。 此數據表會「重建」,並允許安全地套用先前不支援的移轉作業。
如需透過數據表重建支援哪些移轉作業的詳細資訊, 請參閱本文件頁面。
資料庫定序
EF Core 5.0 引進了在資料庫、數據行或查詢層級指定文字定序的支援。 這可讓區分大小寫和其他文字層面以彈性且不會危害查詢效能的方式進行設定。
例如,下列專案會將數據行設定 Name
為區分大小寫的 SQL Server,而且在數據行上建立的任何索引都會據此運作:
modelBuilder
.Entity<User>()
.Property(e => e.Name)
.UseCollation("SQL_Latin1_General_CP1_CS_AS");
如需詳細資訊, 請參閱定序和區分大小寫的完整檔。
事件計數器
EF Core 5.0 公開 事件計數器 ,可用來追蹤應用程式的效能,並找出各種異常狀況。 只要使用 dotnet-counters 工具附加至執行 EF 的行程 :
> dotnet counters monitor Microsoft.EntityFrameworkCore -p 49496
[Microsoft.EntityFrameworkCore]
Active DbContexts 1
Execution Strategy Operation Failures (Count / 1 sec) 0
Execution Strategy Operation Failures (Total) 0
Optimistic Concurrency Failures (Count / 1 sec) 0
Optimistic Concurrency Failures (Total) 0
Queries (Count / 1 sec) 1,755
Queries (Total) 98,402
Query Cache Hit Rate (%) 100
SaveChanges (Count / 1 sec) 0
SaveChanges (Total) 1
如需詳細資訊, 請參閱事件計數器的完整檔。
其他功能
模型建置
- 已引進模型建置 API,以便更輕鬆地設定 值比較子。
- 計算數據行現在可以設定為 預 存或 虛擬。
- 有效位數和小數字數現在可以透過 Fluent API 進行設定。
- 已針對導覽屬性引進新的模型建置 API。
- 已針對欄位引進新的模型建置 API,類似於屬性。
- .NET PhysicalAddress 和 IPAddress 類型現在可以對應至資料庫字串數據行。
- 現在可透過 新的
[BackingField]
屬性來設定支援字段。 - 現在允許可為 Null 的支援字段,為存放區產生的預設值提供更好的支援,其中 CLR 預設值不是良好的 sentinel 值(值得注意
bool
)。 - 您可以在實體類型上使用新的
[Index]
屬性來指定索引,而不是使用 Fluent API。 - 新的
[Keyless]
屬性可用來將實體類型 設定為沒有索引鍵。 - 根據預設, EF Core 現在會將歧視性 視為完整,這表示它預期永遠不會在模型中看到應用程式未設定的歧視性值。 這可讓您改善一些效能,而且如果您的歧視性數據行可能保留未知的值,則可以停用。
Query
- 查詢轉譯失敗例外狀況現在包含失敗原因的更明確原因,以協助找出問題。
- 無追蹤查詢現在可以執行 身分識別解析,避免針對相同的資料庫對象傳回多個實體實例。
- 已新增對 GroupBy 的支援,其中包含條件式匯總(例如
GroupBy(o => o.OrderDate).Select(g => g.Count(i => i.OrderDate != null))
)。 - 已新增在匯總之前將 Distinct 運算符轉譯至群組元素的支援。
- 的
Reverse
翻譯。 - 改善 SQL Server 的翻譯
DateTime
功能(例如DateDiffWeek
、DateFromParts
。 - 位元組數位上新方法的翻譯(例如
Contains
、Length
、SequenceEqual
。 - 轉譯一些額外的位運算符,例如兩個的補碼。
- 透過字串的
FirstOrDefault
轉譯。 - 改善 Null 語意的查詢轉譯,進而產生更緊密且更有效率的查詢。
- 用戶對應的函式現在可以加上批注來控制 Null 傳播,再次導致更緊密且更有效率的查詢。
- 包含 CASE 區塊的 SQL 現在更為簡潔。
- SQL Server
DATALENGTH
函式現在可以透過新的EF.Functions.DataLength
方法在查詢中呼叫。 EnableDetailedErrors
將其他詳細數據新增 至例外狀況。
儲存中
- SaveChanges 攔截 和 事件。
- 已導入用於控制交易儲存 點的 API。 此外,EF Core 會在呼叫 時
SaveChanges
自動建立儲存點,且交易正在進行中,並在發生失敗時回復至該儲存點。 - 應用程式可以明確設定交易標識碼,以方便記錄和其他地方的交易事件相互關聯。
- SQL Server 的預設批次大小上限已根據批處理效能的分析變更為 42。
移轉和 Scaffolding
- 數據表現在可以 從移轉中排除。
- 新的
dotnet ef migrations list
命令現在會顯示哪些移轉尚未套用至資料庫(Get-Migration
在套件管理控制台中也是如此)。 - 移轉文本現在包含適當的交易語句,以改善移轉應用程式失敗的處理案例。
- 未對應的基類數據行現在會依對應實體類型的其他數據行排序。 請注意,這隻會影響新建立的數據表;現有數據表的數據行順序保持不變。
- 移轉產生現在可以知道產生的移轉是否具有等冪性,以及輸出是否會立即執行或產生為腳本。
- 已新增新的命令行參數,以在移轉和 Scaffolding 中指定命名空間。
- dotnet ef 資料庫更新命令現在接受新的
--connection
參數來指定 連接字串。 - Scaffolding 現有的資料庫現在會單數化數據表名稱,因此名為
People
和的數據表會建構為稱為Person
和Addresses
Address
的實體類型。 原始資料庫名稱仍可保留。 - 新的
--no-onconfiguring
選項可以指示 EF Core 在建構模型時排除OnConfiguring
。
Azure Cosmos DB
- Azure Cosmos DB 連線設定 已展開。
- Azure Cosmos DB 現在 透過使用 ETag 支援開放式並行存取。
- 新的
WithPartitionKey
方法可讓 Azure Cosmos DB 分割區索引鍵 同時包含在模型和查詢中。 - 字串方法
Contains
,StartsWith
現在EndsWith
會轉譯為 Azure Cosmos DB。 - C#
is
運算子現在會在 Azure Cosmos DB 上轉譯。
Sqlite
- 現在支援計算數據行。
- 使用 GetBytes、GetChars 和 GetTextReader 擷取二進位和字串數據現在更有效率,方法是使用 SqliteBlob 和數據流。
- SqliteConnection 的初始化現在為延遲。
其他
- 您可以產生變更追蹤 Proxy,以自動實 作 INotifyPropertyChanging 和 INotifyPropertyChanged。 這提供變更追蹤的替代方法,不會在呼叫 時
SaveChanges
掃描變更。 - DbConnection或 連接字串 現在可以在已初始化的 DbContext 上變更。
- 新的 ChangeTracker.Clear 方法會清除所有追蹤實體的 DbContext。 使用為每個工作單位建立新的短期內容實例的最佳做法時,通常不需要這樣做。 不過,如果需要重設 DbContext 實例的狀態,則使用新
Clear()
方法比大規模中斷連結所有實體更有效率且強固。 - EF Core 命令行工具現在會自動將
ASPNETCORE_ENVIRONMENT
和DOTNET_ENVIRONMENT
環境變數設定為「開發」。 這讓在開發期間使用泛型主機時的體驗與 ASP.NET Core 的體驗一致。 - 自定義命令行自變數可以流入 IDesignTimeDbContextFactory<TContext>,讓應用程式能夠控制內容的建立和初始化方式。
- 現在可以 在 SQL Server 上設定索引填滿因數。
- 使用關係提供者和非關聯提供者時,可以使用新的 IsRelational 屬性來區別 (例如記憶體內部提供者)。