efcore 新特性 SaveChanges Events
Intro
昨天早上看到之前关注的一个 efcore 的 issue 被 closed ,于是看了一眼, ef core 新合并了一个 PR,在 DbContext
中增加了 SaveChanges
相关的几个事件,具体的变更可以参数 PR https://github.com/dotnet/efcore/pull/21862
Events
之前写过两篇关于 EF Core 做自动审计的文章
第一次的实现需要显式继承一个 AuditDbContext
,在有些需要没办法修改 DbContext
或者原有 DbContext
已经有继承某一个类,就没有办法用了,可以参考 EF Core 数据变更自动审计设计
后面结合 AOP 改进了一版,通过一个审计切面逻辑完成自动审计,但是需要引入 AOP 组件支持,对于不想引入额外组件的项目来说也并非特别友好,可以参考 打造更好用的 EF 自动审计
在这个 PR 合并之后,我们可以通过 SavingChanges
事件获取保存之前 DbContext
的状态,通过 SavedChanges
事件来获取保存成功后的 DbContext
信息,SaveChangesFailed
事件获取保存失败信息
事件定义如下:
/// <summary>
/// An event fired at the beginning of a call to <see cref="M:SaveChanges"/> or <see cref="M:SaveChangesAsync"/>
/// </summary>
public event EventHandler<SavingChangesEventArgs> SavingChanges;/// <summary>
/// An event fired at the end of a call to <see cref="M:SaveChanges"/> or <see cref="M:SaveChangesAsync"/>
/// </summary>
public event EventHandler<SavedChangesEventArgs> SavedChanges;/// <summary>
/// An event fired if a call to <see cref="M:SaveChanges"/> or <see cref="M:SaveChangesAsync"/> fails with an exception.
/// </summary>
public event EventHandler<SaveChangesFailedEventArgs> SaveChangesFailed;
事件参数定义如下:
/// <summary>
/// Base event arguments for the <see cref="M:DbContext.SaveChanges" /> and <see cref="M:DbContext.SaveChangesAsync" /> events.
/// </summary>
public abstract class SaveChangesEventArgs : EventArgs
{/// <summary>/// Creates a base event arguments instance for <see cref="M:DbContext.SaveChanges" />/// or <see cref="M:DbContext.SaveChangesAsync" /> events./// </summary>/// <param name="acceptAllChangesOnSuccess"> The value passed to SaveChanges. </param>protected SaveChangesEventArgs(bool acceptAllChangesOnSuccess){AcceptAllChangesOnSuccess = acceptAllChangesOnSuccess;}/// <summary>/// The value passed to <see cref="M:DbContext.SaveChanges" /> or <see cref="M:DbContext.SaveChangesAsync" />./// </summary>public virtual bool AcceptAllChangesOnSuccess { get; }
}/// <summary>
/// Event arguments for the <see cref="DbContext.SavingChanges" /> event.
/// </summary>
public class SavingChangesEventArgs : SaveChangesEventArgs
{/// <summary>/// Creates event arguments for the <see cref="M:DbContext.SavingChanges" /> event./// </summary>/// <param name="acceptAllChangesOnSuccess"> The value passed to SaveChanges. </param>public SavingChangesEventArgs(bool acceptAllChangesOnSuccess): base(acceptAllChangesOnSuccess){}
}/// <summary>
/// Event arguments for the <see cref="DbContext.SavedChanges" /> event.
/// </summary>
public class SavedChangesEventArgs : SaveChangesEventArgs
{/// <summary>/// Creates a new <see cref="SavedChangesEventArgs" /> instance with the given number of entities saved./// </summary>/// <param name="acceptAllChangesOnSuccess"> The value passed to SaveChanges. </param>/// <param name="entitiesSavedCount"> The number of entities saved. </param>public SavedChangesEventArgs(bool acceptAllChangesOnSuccess, int entitiesSavedCount) : base(acceptAllChangesOnSuccess){EntitiesSavedCount = entitiesSavedCount;}/// <summary>/// The number of entities saved./// </summary>public virtual int EntitiesSavedCount { get; }
}/// <summary>
/// Event arguments for the <see cref="DbContext.SaveChangesFailed" /> event.
/// </summary>
public class SaveChangesFailedEventArgs : SaveChangesEventArgs
{/// <summary>/// Creates a new <see cref="SaveChangesFailedEventArgs"/> instance with the exception that was thrown./// </summary>/// <param name="acceptAllChangesOnSuccess"> The value passed to SaveChanges. </param>/// <param name="exception"> The exception thrown. </param>public SaveChangesFailedEventArgs(bool acceptAllChangesOnSuccess, [NotNull] Exception exception): base(acceptAllChangesOnSuccess){Exception = exception;}/// <summary>/// The exception thrown during<see cref="M:DbContext.SaveChanges"/> or <see cref="M:DbContext.SaveChangesAsync"/>./// </summary>public virtual Exception Exception { get; }
}
More
除了上面的审计,你也可以使用通过这些事件,实现保存之前的自动更新数据库字段的值,比如 Add
或 Update
操作数据时自动设置更新时间等信息
本文提到的特性还未正式发布,预计会在 .net5 下一个预览版中发布,如果想现在要尝试,请使用 efcore 的 daily build 的包,可以参考 https://github.com/dotnet/aspnetcore/blob/master/docs/DailyBuilds.md
Reference
https://github.com/dotnet/efcore/issues/15910
https://github.com/dotnet/efcore/pull/21862