You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core使用Dapper更新数据库时Audit日志新旧值相同问题

问题原因
  • 核心原因1:AuditScope 默认的对象读取时机错误
    你使用的AuditScope.Create("Role:Create", () => roleEntity)重载,传入的是指向roleEntity实例的引用委托。Audit.NET默认不会在Scope初始化阶段序列化目标对象生成旧值快照,只会在Scope释放(即执行到using块末尾)时才读取委托返回的对象生成审计数据。这种情况下旧值和新值读取的是内存中同一个对象的最终状态,自然完全一致。
  • 核心原因2:目标实体在Scope生命周期内没有发生任何实际变更
    你通过Dapper调用存储过程完成插入操作后,存储过程返回的自增主键Rol_ID_N只存在于Dapper动态参数中,你并没有将这个数据库生成的新值回写赋值到原始roleEntity实例上,整个执行流程中roleEntity的属性值从未改变,即使Audit正确捕获了初始快照,也识别不到任何数据变更。
  • 额外配置坑:部分版本的Audit.NET默认关闭了初始状态序列化开关
    如果你没有显式给AuditScope配置SerializeInitialState = true,组件不会自动保存对象的初始状态副本,只会记录最终状态,自然无法生成新旧值对比。
修复方案
  1. 强制开启AuditScope初始化时的初始状态快照,修改Scope创建代码如下:
// 可选:如果担心组件默认深拷贝逻辑有问题,可以提前手动生成初始值副本
var initialValue = JsonSerializer.Deserialize<RoleEntity>(JsonSerializer.Serialize(roleEntity));
using var scope = AuditScope.Create("Role:Create", () => roleEntity, new AuditScopeOptions
{
    // 关键配置:Scope创建时立刻序列化目标对象生成旧值快照
    SerializeInitialState = true,
    EventCreationPolicy = EventCreationPolicy.InsertOnEnd
});
  1. 数据库操作完成后,将所有数据库生成的字段值回写到原始roleEntity实例,保证新值和旧值存在可识别的差异:
param.Add("@VAR_MODE_V", DBStoredProcedure.OperationMode.INSERT);
param.Add("@Rol_ID_N", roleEntity.Rol_ID_N, dbType: DbType.Int32, direction: ParameterDirection.InputOutput);
var result = await this._adlerMDBContext.QueryAsync<AdlerSPResponseMessage>(DBStoredProcedure.Role.SPName, AddUserResolverParam(param), commandType: CommandType.StoredProcedure);
var roleId = param.Get<int>("@Rol_ID_N");

// 关键:将数据库生成的主键回写到原实体
roleEntity.Rol_ID_N = roleId;

if (result?.FirstOrDefault()?.Status == false)
{
    AdlERMLogError($"{errorPrefix}/{nameof(AddAsync)} Exception - {FormatErrorMessage(result)}", null);
}

return new AdlerResponse<int,long>()
{
    Code = Convert.ToInt32(result?.FirstOrDefault()?.Code),
    Status = result?.FirstOrDefault()?.Status,
    Severity = MessageSeverity((int)result?.FirstOrDefault()?.Code),
    Data = result?.FirstOrDefault()?.TotalRows ?? 0,
    DataId = roleId,
    Messages = GetResponseMessages(result),
    Rows = result?.FirstOrDefault()?.TotalRows ?? 0
};
  1. 如果后续做更新操作,必须在执行数据库更新命令之前创建AuditScope,不要在更新执行完成后再创建Scope,否则内存中的实体已经被新值覆盖,无法捕获正确的旧值。

内容的提问来源于stack exchange,提问作者Seena N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 09:18:27