我正在查看 C# 的干净架构解决方案模板,可在 Github 上获取此处。
我需要澄清的类是
AuditableEntityInterceptor
类,其源代码可在 here 获得。
拦截器的代码如下:
public class AuditableEntityInterceptor : SaveChangesInterceptor
{
private readonly IUser _user;
private readonly TimeProvider _dateTime;
public AuditableEntityInterceptor(
IUser user,
TimeProvider dateTime)
{
_user = user;
_dateTime = dateTime;
}
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
{
UpdateEntities(eventData.Context);
return base.SavingChanges(eventData, result);
}
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
{
UpdateEntities(eventData.Context);
return base.SavingChangesAsync(eventData, result, cancellationToken);
}
public void UpdateEntities(DbContext? context)
{
if (context == null) return;
foreach (var entry in context.ChangeTracker.Entries<BaseAuditableEntity>())
{
if (entry.State is EntityState.Added or EntityState.Modified || entry.HasChangedOwnedEntities())
{
var utcNow = _dateTime.GetUtcNow();
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedBy = _user.Id;
entry.Entity.Created = utcNow;
}
entry.Entity.LastModifiedBy = _user.Id;
entry.Entity.LastModified = utcNow;
}
}
}
}
public static class Extensions
{
public static bool HasChangedOwnedEntities(this EntityEntry entry) =>
entry.References.Any(r =>
r.TargetEntry != null &&
r.TargetEntry.Metadata.IsOwned() &&
(r.TargetEntry.State == EntityState.Added || r.TargetEntry.State == EntityState.Modified));
}
此 EF 核心拦截器旨在在数据库上下文实例上调用方法
SaveChanges()
和 SaveChangesAsync()
时运行一些逻辑。基本上,这个想法是能够自动设置由基类 CreatedBy
(用作任何实体的基类)定义的审核字段 Created
、LastModifiedBy
、LastModified
和 BaseAuditableEntity
的值这需要审核能力)。
我无法完全理解的代码是名为
HasChangedOwnedEntities()
的方法。entry.State is EntityState.Added or EntityState.Modified
表示的条件不足以足以识别在当前工作单元期间添加或修改的任何实体?
我的理解是,
HasChangedOwnedEntities()
方法的目的是检测必须被视为“已修改”的实体,因为在当前工作单元中至少有一个“拥有的实体”已被修改。
我的理解正确吗?
为什么仅仅检查条件entry.State == EntityState.Modified
不足以识别这些实体?
因为如果只更改拥有的实体,那么拥有的实体将被视为未更改,只有拥有的实体才会被标记为已修改。检查起来非常简单:public class Owner { public int Id { get; set; } public Owned Owned { get; set; } } [Owned] public class Owned { public string? Data { get; set; } }
var owner = ctx.Owners.First();
owner.Owned.Data = "Updated" + Guid.NewGuid();
Console.WriteLine(ctx.Owners.Entry(owner).State); // prints "Unchanged"
Console.WriteLine(ctx.Entry(owner.Owned).State); // prints "Modified"