.NET Core中获取IdentityDbContext实体变更前版本用于日志
解决.NET Core IdentityDbContext中获取实体变更前版本的问题
我明白你现在的困境——在.NET Core的IdentityDbContext里搭建实体变更日志功能,却因为找不到EF6里的ObjectStateManager卡壳了。那个老方案是针对Entity Framework 6的,而EF Core的API已经不一样了,咱们换个思路来解决:
核心思路:用EF Core的ChangeTracker替代ObjectStateManager
EF Core里的DbContext(包括IdentityDbContext)自带ChangeTracker,它能追踪所有实体的状态变化,我们可以通过它获取变更前后的实体版本。
具体实现步骤
重写IdentityDbContext的保存方法
因为IdentityDbContext继承自DbContext,我们可以重写SaveChanges或SaveChangesAsync方法,在保存数据前拦截并获取变更信息。获取变更前的实体版本
对于状态为EntityState.Modified的实体,使用GetDatabaseValues()方法可以从数据库中获取该实体的原始(变更前)数据,再和当前实体的CurrentValues对比就能拿到差异。
示例代码
下面是一个重写SaveChanges的示例,你可以根据自己的日志需求调整逻辑:
public class AppIdentityDbContext : IdentityDbContext { // 构造函数等其他代码... public override int SaveChanges(bool acceptAllChangesOnSuccess) { // 捕获所有被修改的实体 var modifiedEntities = ChangeTracker.Entries() .Where(entry => entry.State == EntityState.Modified) .ToList(); foreach (var entry in modifiedEntities) { // 获取数据库中存储的原始实体版本 var originalValues = entry.GetDatabaseValues(); if (originalValues != null) { // 将原始值转换为实体对象 var originalEntity = originalValues.ToObject(); // 当前修改后的实体 var currentEntity = entry.Entity; // 这里执行你的日志逻辑:比如对比两个实体的属性差异,保存到日志表 // 例如:LogEntityChange(originalEntity, currentEntity); } } // 调用基类方法完成保存 return base.SaveChanges(acceptAllChangesOnSuccess); } // 异步版本的重写同理 public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) { var modifiedEntities = ChangeTracker.Entries() .Where(entry => entry.State == EntityState.Modified) .ToList(); foreach (var entry in modifiedEntities) { var originalValues = await entry.GetDatabaseValuesAsync(cancellationToken); if (originalValues != null) { var originalEntity = originalValues.ToObject(); var currentEntity = entry.Entity; // 异步日志逻辑 // await LogEntityChangeAsync(originalEntity, currentEntity, cancellationToken); } } return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); } }
额外说明
- 除了修改的实体,你也可以用同样的方式处理
EntityState.Added(新增)和EntityState.Deleted(删除)的实体:新增的实体没有原始值,删除的实体可以直接用entry.Entity作为删除前的版本。 GetDatabaseValues()会发起数据库查询,如果你的系统对性能敏感,可以考虑只针对需要日志的实体类型做处理,避免不必要的查询。
内容的提问来源于stack exchange,提问作者Dat Nguyen
相关产品推荐
相关产品推荐

