文章目錄
- 一、 新功能
- 1. 支援臨時表(時态表)
- 2. 預編譯的模型
- 3. 性能提升
- 4. 一些對Cosmos的改進支援
- 5. 支援可空引用類型
- 6. DbFirst模式支援将資料庫裡注釋添加到實體屬性上
- 7. [PrecisionAttribute],用來配置資料庫列的精度
- 8. [EntityTypeConfiguration]特性
- 9. 多對多實體關系配置簡化
- 二、中斷性變更
EF Core本次更新了不少東西,大概看了一下,對一些自我感覺比較常用的内容做了一些羅列,未盡之處還請閱讀官方完整文檔:https://docs.microsoft.com/zh-cn/ef/core/what-is-new/ef-core-6.0/whatsnew
一、 新功能
1. 支援臨時表(時态表)
支援建立和使用時态表(SQL Server 2016新增的功能),現在已經支援了下述幾個功能:
- 使用遷移建立時态表
- 再次使用遷移将現有表轉換為時态表
- 查詢曆史資料
- 從過去某個時間點還原資料
如果在項目裡有使用時态表,可轉到詳情繼續閱讀。
2. 預編譯的模型
我們知道應用在首次使用DbContext時會花費一定的時間來初始化ef模型,僅建立DbContext執行個體不會初始化ef模型,隻有當執行Add、第一個查詢、等操作時才會初始化。如果你的模型很大,有幾百幾千種實體和對應關系,那麼初始化操作時間可能就會比較長。
解決這個問題一般有兩種方式:
- 提前觸發初始化,比如在Startup裡,或者在應用啟動之後手動觸發一次。
- 使用本次版本新增預編譯功能。
這裡我就隻介紹第二點了。
首先,使用
dotnet ef dbcontext optimize
指令生成預編譯的模型(
--output-dir
和
--namespace
參數指定輸出目錄和模型的命名空間)。此指令會傳回一段提示資訊,提示資訊裡會告訴你怎麼用。
PS C:\dotnet\efdocs\samples\core\Miscellaneous\CompiledModels> dotnet ef dbcontext optimize --output-dir MyCompiledModels --namespace MyCompiledModels
Build started...
Build succeeded.
Successfully generated a compiled model, to use it call 'options.UseModel(MyCompiledModels.BlogsContextModel.Instance)'. Run this command again when the model is modified.
然後,将上述提示的代碼配置到到dbcontext上:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseModel(MyCompiledModels.BlogsContextModel.Instance)
.UseSqlite(@"Data Source=test.db");
最後,預編譯的模型也有一些不足:
- 不支援全局查詢篩選器。
- 不支援延遲加載和更改跟蹤代理。
- 不支援自定義 IModelCacheKeyFactory 實作。 但是,可以編譯多個模型,并根據需要加載相應的模型。
- 在模型定義或配置更改時,必須重新生成模型來手動同步模型。
由于這些不足,隻應在 EF Core 啟動時間太慢時使用已編譯的模型。 編譯小型模型通常不太值得使用已編譯的模型。
預編譯的模型到底提升了多少性能?
微軟給出來一個示例代碼,包含 449 種實體類型、6390 個屬性和 720 種關系。 這是一個中等大小的模型。 使用 BenchmarkDotNet 進行度量,首次查詢的平均時間為 1.02 秒。 在相同的硬體上,使用已編譯的模型可将這一時間縮短到 117 毫秒。 随着模型大小的增加,會保持類似這樣相對穩定的 8 到 10 倍的改進。
3. 性能提升
對ef的查詢性能進行了巨大改進,包括:
- efcore 6.0 比 efcore 5.0在TechEmpower Fortunes基準測試中,得力于.net6比.net5的性能提升+ef6比ef5的性能提升+測試項優化,總體大概快了70%。
- ef6的AsNoTracking查詢提升了31%。
- 查詢時,堆配置設定時間減少了43%。
經過上述改進之後Dapper和ef的差距從55%縮減到了5%以下。
詳見這裡
4. 一些對Cosmos的改進支援
如果用到了cosmos db可以閱讀官方博文
5. 支援可空引用類型
現在支援把
public string? Description { get; set; }
資料庫設定為可空類型。
6. DbFirst模式支援将資料庫裡注釋添加到實體屬性上
public partial class Blog
{
/// <summary>
/// 這裡是資料庫裡的字段注釋
/// </summary>
[Key]
public int Id { get; set; }
}
7. [PrecisionAttribute],用來配置資料庫列的精度
可以使用
PrecisionAttribute
來配置資料庫列的精度和小數位的個數:
public class Product
{
public int Id { get; set; }
//精度為10, 2位小數
[Precision(precision: 10, scale: 2)]
public decimal Price { get; set; }
}
8. [EntityTypeConfiguration]特性
IEntityTypeConfiguration<TEntity>
允許将每個實體類型的
ModelBuilder
配置包含在其各自的配置類中。如:
public class BookConfiguration : IEntityTypeConfiguration<Book>
{
public void Configure(EntityTypeBuilder<Book> builder)
{
builder
.Property(e => e.Isbn)
.IsUnicode(false)
.HasMaxLength(22);
}
}
然後執行個體化并進行配置:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
new BookConfiguration().Configure(modelBuilder.Entity<Book>());
}
最後,添加特性:
[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Isbn { get; set; }
}
以後每當模型中包含 Book 實體類型時,EF Core 都将使用指定的
IEntityTypeConfiguration
實作
9. 多對多實體關系配置簡化
比如如下的配置,會産生一個中間表:
modelBuilder.Entity<Cat>()
.HasMany(e => e.Humans)
.WithMany(e => e.Cats);
從ef6開始,你可以使用
UsingEntity
簡化手動指定實體的配置:
modelBuilder.Entity<Cat>()
.HasMany(e => e.Humans)
.WithMany(e => e.Cats)
.UsingEntity<CatHuman>();
也可以進行完整配置:
modelBuilder.Entity<Cat>()
.HasMany(e => e.Humans)
.WithMany(e => e.Cats)
.UsingEntity<CatHuman>(
e => e.HasOne<Human>().WithMany().HasForeignKey(e => e.CatsId),
e => e.HasOne<Cat>().WithMany().HasForeignKey(e => e.HumansId),
e => e.HasKey(e => new { e.CatsId, e.HumansId }));