天天看點

Entity Framework Core 6.0 中的新功能介紹

文章目錄

  • ​​一、 新功能​​
  • ​​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、第一個查詢、等操作時才會初始化。如果你的模型很大,有幾百幾千種實體和對應關系,那麼初始化操作時間可能就會比較長。

解決這個問題一般有兩種方式:

  1. 提前觸發初始化,比如在Startup裡,或者在應用啟動之後手動觸發一次。
  2. 使用本次版本新增預編譯功能。

這裡我就隻介紹第二點了。

首先,使用​​

​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的查詢性能進行了巨大改進,包括:

  1. efcore 6.0 比 efcore 5.0在TechEmpower Fortunes基準測試中,得力于.net6比.net5的性能提升+ef6比ef5的性能提升+測試項優化,總體大概快了70%。
  2. ef6的AsNoTracking查詢提升了31%。
  3. 查詢時,堆配置設定時間減少了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 }));      

二、中斷性變更