小窍门
可以从 GitHub 下载事件示例 。
实体框架核心(EF Core)提供 .NET 事件,用于在 EF Core 代码中发生某些特定情况时作为回调函数。 事件比 侦听器 更简单,并且允许更灵活的注册。 但是,它们仅支持同步,因此无法执行非阻塞异步 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