Entity Framework Core 7 自動紀錄資料表的 建立時間和修改時間

之前我們有介紹過 Entity Framework Core 7 紀錄整個系統的資料變更 詳記示範,本篇要介紹的是在每個資料表中都加上建立時間和修改時間,當資料建立和修改時就會自動更新時間欄位的方式。

首先在資料庫的部分逃不了,每個資料表都需要加上這兩個欄位:
    
create table MyTable
(
    CreatedAt datetime default getdate() not null,
    UpdatedAt datetime default getdate() not null
)
    

建立一個介面,把所有要加上這兩個時間的資料庫對應實體都繼承這個介面:
    
public interface IEntity
{
    [Column(TypeName = "datetime")] DateTime CreatedAt { get; set; }
    [Column(TypeName = "datetime")] DateTime UpdatedAt { get; set; }
}
    

建立一個自訂的儲存攔截器,繼承 SaveChangesInterceptor ,然後覆寫 SavingChanges 和 SavingChangesAsync 方法。只要變更的實體是繼承 IEntity ,就要依據是建立還是更新來填入建立和更新日期。
    
public class TimestampsSaveChangesInterceptor : SaveChangesInterceptor
{
    public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
    {
        SetEntityDateTime(eventData);
        return base.SavingChanges(eventData, result);
    }

    public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
        DbContextEventData eventData, InterceptionResult<int> result,
        CancellationToken cancellationToken = new CancellationToken()
    )
    {
        SetEntityDateTime(eventData);
        return base.SavingChangesAsync(eventData, result, cancellationToken);
    }

    private void SetEntityDateTime(DbContextEventData eventData)
    {
        if (eventData.Context == null) return;
        var entries = eventData.Context.ChangeTracker.Entries();
        foreach (var entry in entries)
        {
            if (entry.Entity is not IEntity entity) continue;

            if (entry.State == EntityState.Added)
            {
                entity.CreatedAt = DateTime.UtcNow;
                entity.UpdatedAt = DateTime.UtcNow;
            }
            else if (entry.State == EntityState.Modified)
            {
                entity.UpdatedAt = DateTime.UtcNow;
            }
        }
    }
}
    

最後在 ApplicationDbContext 中的 OnConfiguring 加上攔截器即可。
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseSqlServer("Name=ConnectionStrings:DefaultConnection")
            .AddInterceptors(new TimestampsSaveChangesInterceptor());
    



參考資料:
Microsoft.Learn - SaveChangesInterceptor Class

留言