EF Core 中的 .NET 事件

提示

您可以從 GitHub 下載事件範例

Entity Framework Core (EF Core) 會在 EF Core 程式碼中發生某些情況時,公開 .NET 事件 作為回呼。 事件比 攔截器 簡單,而且允許更有彈性的註冊。 不過,它們只是同步處理,因此無法執行非封鎖非同步 I/O。

每個 DbContext 實例都會註冊事件。 使用診斷接聽程式來取得相同的資訊,但是是針對處理序中的所有 DbCoNtext 執行個體。

EF Core 所引發的事件

EF Core 會引發下列事件:

Event 引發時
DbContext.SavingChanges 或 的 SaveChanges 開頭 SaveChangesAsync
DbContext.SavedChanges 成功 SaveChanges 或結尾 SaveChangesAsync
DbContext.SaveChangesFailed 在失敗 SaveChanges 或結束時 SaveChangesAsync
ChangeTracker.Tracked 內容追蹤實體時
ChangeTracker.StateChanged 當追蹤實體變更其狀態時

範例:時間戳記狀態變更

DbCoNtext 追蹤的每個實體都有 EntityState 。 例如, Added 狀態表示實體會插入資料庫中。

這個範例會使用 TrackedStateChanged 事件來偵測實體何時變更狀態。 然後,它會加上實體的戳記,並加上目前時間,指出此變更發生的時間。 這會產生時間戳記,指出實體何時插入、刪除和/或上次更新。

此範例中的實體類型會實作定義時間戳記屬性的介面:

public interface IHasTimestamps
{
    DateTime? Added { get; set; }
    DateTime? Deleted { get; set; }
    DateTime? Modified { get; set; }
}

接著,應用程式 DbCoNtext 上的方法可以設定任何實作此介面之實體的時間戳記:

private static void UpdateTimestamps(object sender, EntityEntryEventArgs e)
{
    if (e.Entry.Entity is IHasTimestamps entityWithTimestamps)
    {
        switch (e.Entry.State)
        {
            case EntityState.Deleted:
                entityWithTimestamps.Deleted = DateTime.UtcNow;
                Console.WriteLine($"Stamped for delete: {e.Entry.Entity}");
                break;
            case EntityState.Modified:
                entityWithTimestamps.Modified = DateTime.UtcNow;
                Console.WriteLine($"Stamped for update: {e.Entry.Entity}");
                break;
            case EntityState.Added:
                entityWithTimestamps.Added = DateTime.UtcNow;
                Console.WriteLine($"Stamped for insert: {e.Entry.Entity}");
                break;
        }
    }
}

這個方法具有適當的簽章,可用來作為 和 StateChanged 事件的事件處理常式 Tracked 。 處理常式會在 DbCoNtext 建構函式中註冊這兩個事件。 請注意,事件可以隨時附加至 DbCoNtext;這不需要在內容建構函式中發生。

public BlogsContext()
{
    ChangeTracker.StateChanged += UpdateTimestamps;
    ChangeTracker.Tracked += UpdateTimestamps;
}

這兩個事件都是必要的,因為新實體會在第一次追蹤事件時引發 Tracked 事件。 StateChanged 事件只會針對在追蹤時 變更狀態的實體引發。

此範例的範例 包含對部落格資料庫進行變更的簡單主控台應用程式:

using (var context = new BlogsContext())
{
    context.Database.EnsureDeleted();
    context.Database.EnsureCreated();

    context.Add(
        new Blog
        {
            Id = 1,
            Name = "EF Blog",
            Posts = { new Post { Id = 1, Title = "EF Core 3.1!" }, new Post { Id = 2, Title = "EF Core 5.0!" } }
        });

    context.SaveChanges();
}

using (var context = new BlogsContext())
{
    var blog = context.Blogs.Include(e => e.Posts).Single();

    blog.Name = "EF Core Blog";
    context.Remove(blog.Posts.First());
    blog.Posts.Add(new Post { Id = 3, Title = "EF Core 6.0!" });

    context.SaveChanges();
}

此程式碼的輸出會顯示狀態變更,以及所套用的時間戳記:

Stamped for insert: Blog 1 Added on: 10/15/2020 11:01:26 PM
Stamped for insert: Post 1 Added on: 10/15/2020 11:01:26 PM
Stamped for insert: Post 2 Added on: 10/15/2020 11:01:26 PM
Stamped for delete: Post 1 Added on: 10/15/2020 11:01:26 PM Deleted on: 10/15/2020 11:01:26 PM
Stamped for update: Blog 1 Added on: 10/15/2020 11:01:26 PM Modified on: 10/15/2020 11:01:26 PM
Stamped for insert: Post 3 Added on: 10/15/2020 11:01:26 PM