efcore 新特性 SaveChanges Events efcore 新特性 SaveChanges Events

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 已經有繼承某一個類,就沒有辦法用了

後面使用 AOP 改進了一版,通過一個審計切面邏輯完整自動審計,但是需要引入 AOP 組件支持,對於不想引入額外組件的項目來說也並非特別友好

在這個變更之後,我們可以通過 SavingChanges 事件獲取保存之前 DbContext 的狀態,通過 SavedChanges 事件來獲取保存成功的事件,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

除了上面的審計,你也可以使用通過這些事件,實現保存之前的自動更新數據庫字段的值,比如 AddUpdate 操作數據時自動設置更新時間等信息

本文提到的特性還未正式發佈,預計會在 .net5 下一個預覽版中發佈,如果想現在要嘗試,請使用 efcore 的 daily build 的包,可以參考 https://github.com/dotnet/aspnetcore/blob/master/docs/DailyBuilds.md

Reference

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章