簡體   English   中英

實體框架核心創建和更新字段

[英]Entity Framework Core Creation and Update fields

我的所有實體上都有四個自定義字段。 這四個字段是CreatedByCreatedDateUpdatedByUpdatedDate

有沒有辦法掛鈎到 Entity Framework 核心事件,以便在插入時它將使用當前的DateTime填充CreatedDate並使用當前用戶填充CreatedBy 當數據庫有更新時,它會用當前的DateTime填充UpdatedDate ,用當前用戶填充UpdatedBy

基本上@Steve 的方法是可行的方法,但它的當前實現使得對您的項目進行單元測試變得困難。

通過一點點重構,您可以使其單元測試友好,並忠於 SOLID 原則和封裝。

這是 Steve 示例的重構版本

public abstract class AuditableEntity
{
    public DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }
    public DateTime UpdatedDate { get; set; }
    public string UpdatedBy { get; set; }
}

public class AuditableDbContext : DbContext
{
    protected readonly IUserService userService;
    protected readonly DbContextOptions options;
    protected readonly ITimeService timeService;

    public BaseDbContext(DbContextOptions options, IUserService userService, ITimeService timeService) : base(options)
    {
        userService = userService ?? throw new ArgumentNullException(nameof(userService));
        timeService = timeService ?? throw new ArgumentNullException(nameof(timeService));
    }

    public override int SaveChanges()
    {
        // get entries that are being Added or Updated
        var modifiedEntries = ChangeTracker.Entries()
                .Where(x => (x.State == EntityState.Added || x.State == EntityState.Modified));

        var identityName = userService.CurrentUser.Name;
        var now = timeService.CurrentTime;

        foreach (var entry in modifiedEntries)
        {
            var entity = entry.Entity as AuditableEntity;

            if (entry.State == EntityState.Added)
            {
                entity.CreatedBy = identityName ?? "unknown";
                entity.CreatedDate = now;
            }

            entity.UpdatedBy = identityName ?? "unknown";
            entity.UpdatedDate = now;
        }

        return base.SaveChanges();
    }
}

現在很容易模擬單元測試的時間和用戶/主體,並且模型/域/業務層沒有 EF Core 依賴,更好地封裝您的域邏輯。

當然,可以通過使用策略模式進一步重構它以使用更模塊化的方法,但這超出了范圍。 您還可以使用 ASP.NET Core Boilerplate,它也提供了可審計(和軟刪除)EF Core DbContext(這里這里)的實現

我和你的布局完全一樣,我稱之為“審計”字段。

我解決這個問題的方法是創建一個名為AuditableEntity的基本抽象類來保存屬性本身並公開一個名為PrepareSave的方法。 PrepareSave我根據需要設置字段的值:

public abstract class AuditableEntity
{
    public DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }
    public DateTime UpdatedDate { get; set; }
    public string UpdatedBy { get; set; }

    public virtual void PrepareSave(EntityState state)
    {
        var identityName = Thread.CurrentPrincipal.Identity.Name;
        var now = DateTime.UtcNow;

        if (state == EntityState.Added)
        {
            CreatedBy = identityName ?? "unknown";
            CreatedDate = now;
        }

        UpdatedBy = identityName ?? "unknown";
        UpdatedDate = now;
    }
}

我將PrepareSave虛擬,因此如果需要,我可以在我的實體中覆蓋它。 您可能需要根據您的實施更改獲取身份的方式。

為了調用它,我在我的DbContext上覆蓋了SaveChanges並在每個正在添加或更新的實體上調用PrepareSave (我從更改跟蹤器中獲得):

public override int SaveChanges()
{
    // get entries that are being Added or Updated
    var modifiedEntries = ChangeTracker.Entries()
            .Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);

    foreach (var entry in modifiedEntries)
    {
        // try and convert to an Auditable Entity
        var entity = entry.Entity as AuditableEntity;
        // call PrepareSave on the entity, telling it the state it is in
        entity?.PrepareSave(entry.State);
    }

    var result = base.SaveChanges();
    return result;
}

現在,每當我在 DbContext 上調用SaveChanges (直接或通過存儲庫)時,任何繼承AuditableEntity實體都會根據需要設置其審計字段。

不幸的是,我在添加評論方面的聲譽很低。 出於這個原因,我添加了我的答案。 所以: 曾回答的一個補充。 當實體處於修改狀態時,您必須設置 IsModidied = false 或 CreatedBy 和 CreatedDate 屬性。 否則,這些字段將被字符串和日期時間類型的可選值重寫。

if (entry.State == EntityState.added)
{
    CreatedBy = identityName ?? "unknown";
    CreatedDate = now;
}
else
{
    Entry<AuditableEntity>(entry).Property(p => p.CreatedBy).IsModified = false;
    Entry<AuditableEntity>(entry).Property(p => p.CreatedDate).IsModified = false;
    // or
    // entity.Property("CreatedBy").IsModified = false;
    // entity.Property("CreatedDate").IsModified = false;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM