实体框架核心创建和更新字段 [英] Entity Framework Core Creation and Update fields
问题描述
我在所有实体上都有四个自定义字段.四个字段是CreatedBy
,CreatedDate
,UpdatedBy
和UpdatedDate
.
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屋!