实体框架核心创建和更新字段 [英] Entity Framework Core Creation and Update fields

查看:56
本文介绍了实体框架核心创建和更新字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在所有实体上都有四个自定义字段.四个字段是CreatedByCreatedDateUpdatedByUpdatedDate.

I have four custom fields on all of my entities. The four fields are CreatedBy, CreatedDate, UpdatedBy and UpdatedDate.

是否有一种方法可以挂接到Entity Framework核心事件,以便在插入时将使用当前的DateTime和当前的用户填充CreatedDate?当数据库有更新时,它将使用当前的DateTime填充UpdatedDate并使用当前的用户填充UpdatedBy吗?

Is there a way to hook into Entity Framework core events so that on an insert it will populate the CreatedDate with the current DateTime and CreatedBy with the current user? When there is an update to the database it would populate UpdatedDate with the current DateTime and UpdatedBy with the current user?

推荐答案

基本上,@ Steve的方法是可行的方法,但是当前的实现使难以对项目进行单元测试.

Basically @Steve's approach is the way to go, but the current implementation of it makes it hard to unit test your project.

只需进行一些重构,就可以使其易于进行单元测试,并忠实于SOLID原理和封装.

With a little bit of refactoring, you can make it unit test friendly and stay true to SOLID principles and encapsulation.

这是Steve示例的重构版本

Here's a refactored version of Steve's example

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的依赖,从而更好地封装了域逻辑.

Now it's easy to mock time and user/principal for unit tests and model/domain/business layer is free of EF Core dependency, better encapsulating your domain logic way better.

当然,可以通过使用策略模式将其进一步重构为使用更模块化的方法,但这超出了范围.您还可以使用ASP.NET Core Boilerplate,它也提供可审核(和软删除)EF Core DbContext的实现(此处此处 >)

Of course one could further refactor this to use a more modular approach by using strategy pattern, but that's out of scope. You can also use ASP.NET Core Boilerplate which also offers an implementation of an auditable (and soft delete) EF Core DbContext (here and here)

这篇关于实体框架核心创建和更新字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆