共用方式為


EF Core 中的 .NET 事件

小提示

您可以從 GitHub 下載事件範例

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

每個 DbContext 實例都會註冊事件。 使用 診斷接聽程式 來取得相同的資訊,但針對進程中的所有 DbContext 實例。

EF Core 所引發的事件

EF Core 會引發下列事件:

事件 當引發時
DbContext.SavingChanges SaveChangesSaveChangesAsync開始時
DbContext.SavedChanges 在成功的 SaveChangesSaveChangesAsync 結束時
DbContext.SaveChangesFailed 在失敗於SaveChangesSaveChangesAsync的結束之時
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;
        }
    }
}

這個方法具有適當的簽名,可以作為TrackedStateChanged事件的事件處理程序。 處理程式會在 DbContext 建構函式中註冊這兩個事件。 請注意,事件可以隨時附加至 DbContext;這不需要在內容建構函式中發生。

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

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

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

using (var context = new BlogsContext())
{
    await context.Database.EnsureDeletedAsync();
    await context.Database.EnsureCreatedAsync();

    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!" } }
        });

    await context.SaveChangesAsync();
}

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

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

    await context.SaveChangesAsync();
}

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

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