繁体   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