小提示
您可以從 GitHub 下載事件範例 。
Entity Framework Core (EF Core) 會在 EF Core 程式代碼中發生某些情況時,公開 .NET 事件 作為回呼。 事件比 攔截器 簡單,而且允許更有彈性的註冊。 不過,它們只是同步處理,因此無法執行非封鎖異步 I/O。
每個 DbContext 實例都會註冊事件。 使用 診斷接聽程式 來取得相同的資訊,但針對進程中的所有 DbContext 實例。
EF Core 所引發的事件
EF Core 會引發下列事件:
| 事件 | 當引發時 |
|---|---|
| DbContext.SavingChanges | 在SaveChanges或SaveChangesAsync開始時 |
| DbContext.SavedChanges | 在成功的 SaveChanges 或 SaveChangesAsync 結束時 |
| DbContext.SaveChangesFailed | 在失敗於SaveChanges或SaveChangesAsync的結束之時 |
| ChangeTracker.Tracked | 當上下文追蹤實體時 |
| ChangeTracker.StateChanged | 當追蹤實體變更其狀態時 |
範例:時間戳狀態變更
DbContext 追蹤的每個實體都有 EntityState。 例如, Added 狀態表示實體會插入資料庫中。
這個範例會使用 Tracked 和 StateChanged 事件來偵測實體何時變更狀態。 然後,它會將目前的時間戳記在實體上,顯示此變更發生的時間。 這會產生時間戳,指出實體何時插入、刪除和/或上次更新。
此範例中的實體類型會實作定義時間戳屬性的介面:
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;
}
}
}
這個方法具有適當的簽名,可以作為Tracked和StateChanged事件的事件處理程序。 處理程式會在 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