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 引進 AddDbContextFactoryAddPooledDbContextFactory 註冊處理站,以在應用程式的相依性插入 (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 功能(例如 DateDiffWeekDateFromParts
  • 位元組陣列上新方法的翻譯(例如 ContainsLengthSequenceEqual
  • 轉譯一些額外的位運算子,例如兩個的補數。
  • 透過字串的 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 和 的資料表會建構為稱為 PersonAddressesAddress 的實體類型。 原始資料庫名稱仍可保留
  • 新的 --no-onconfiguring 選項可以指示 EF Core 在建構模型時排除 OnConfiguring

Azure Cosmos DB

Sqlite

  • 現在支援計算資料行。
  • 使用 GetBytes、GetChars 和 GetTextReader 擷取二進位和字串資料現在更有效率,方法是使用 SqliteBlob 和資料流程。
  • Sqlite連線ion 的初始化現在很延遲。

其他

  • 您可以產生變更追蹤 Proxy,以自動實 作 INotifyPropertyChanging INotifyPropertyChanged 。 這提供變更追蹤的替代方法,不會在呼叫 時 SaveChanges 掃描變更。
  • DbConnection或 連接字串現在可以在已初始化的 DbCoNtext 上變更。
  • 新的 ChangeTracker.Clear 方法會清除所有追蹤實體的 DbCoNtext。 使用為每個工作單位建立新的短期內容實例的最佳做法時,通常不需要這樣做。 不過,如果需要重設 DbCoNtext 實例的狀態,則使用新 Clear() 方法比大規模中斷連結所有實體更有效率且強固。
  • EF Core 命令列工具現在會自動將 ASPNETCORE_ENVIRONMENTDOTNET_ENVIRONMENT 環境變數設定為「開發」。 這讓在開發期間使用泛型主機時的體驗與 ASP.NET Core 的體驗一致。
  • 自訂命令列引數可以流入 IDesignTimeDbContextFactory<TContext> ,讓應用程式能夠控制內容的建立和初始化方式。
  • 現在可以 在 SQL Server 上設定索引填滿因數。
  • 使用關係提供者和非關聯提供者時,可以使用新的 IsRelational 屬性來區別 (例如記憶體內部提供者)。