使用SqlTableDependency做表变更日志时如何正确获取提交变更的操作用户
问题核心原因
- 你的
ITableChangeBroadcastService实现类TestData大概率注册为了全局单例,整个应用生命周期仅会初始化一次,构造函数中存储的adUserName永远是第一次触发服务初始化的用户身份,多用户场景下自然不会更新。 SqlTableDependency的OnChanged事件由数据库变更触发,运行在独立的后台线程中,和用户的请求上下文完全隔离,此时访问IHttpContextAccessor拿到的必然是null,无法通过该方式获取操作人。- 该事件的签名由SqlTableDependency框架定义,你无法直接向事件处理方法传入自定义的额外参数。
最优解决方案
通过给业务表增加操作人字段的方式实现身份传递,完全绕开上下文获取的问题,同时兼容非本系统发起的数据库变更场景:
- 给
Origin实体和对应的数据库表增加LastModifiedAdUser字段,用于存储最后一次操作这条记录的用户身份。 - 在用户主动发起数据变更的
UpdateDataAsync方法中,将前端传入的当前操作人用户名赋值给该字段,同步写入数据库。 SqlTableDependency触发变更事件时,直接从返回的最新实体中读取LastModifiedAdUser字段写入变更日志即可。
代码修改示例
1. 扩展Origin实体
public class Origin { // 原有字段保持不变 public int OrigId { get; set; } public string OriginCode { get; set; } public string OriginDesc { get; set; } public bool Inactive { get; set; } public string StateCode { get; set; } public string CountryCode { get; set; } // 新增操作人字段 public string LastModifiedAdUser { get; set; } }
别忘了同步给数据库的Origin表添加同名varchar类型字段。
2. 修改UpdateDataAsync方法
public async Task UpdateDataAsync(Origin origin, string adUserName) { // 更新前先赋值操作人到实体,写入数据库 origin.LastModifiedAdUser = adUserName; using (var conn = new SqlConnection(_connectionString.Value)) { await conn.UpdateAsync(origin); } }
3. 清理TestData类的无效逻辑
public class TestData : ITableChangeBroadcastService, IDisposable { private const string TableName = "Origin"; private SqlTableDependency<Origin> _notifier; private ConnectionString _connectionString; public event TestDataChangeDelegate OnOriginChanged; // 删掉IHttpContextAccessor注入和adUserName存储字段,已经不需要了 private int lastLoggedId; public TestData(ConnectionString connectionString) { _connectionString = connectionString; _notifier = new SqlTableDependency<Origin>(_connectionString.Value, TableName, includeOldValues:true); _notifier.OnChanged += this.TableDependency_Changed; _notifier.Start(); } private async void TableDependency_Changed(object sender, RecordChangedEventArgs<Origin> e) { if (this.OnOriginChanged != null) { this.OnOriginChanged(this, new TestDataChangeEventArgs(e.Entity, e.EntityOldValues)); using (var conn = new SqlConnection(_connectionString.Value)) { // 直接从最新实体中取操作人字段,非本系统变更可以设置默认值 var operatorUser = e.Entity.LastModifiedAdUser ?? "系统操作"; lastLoggedId = await conn.LogChangeAsync(e.Entity, e.EntityOldValues, operatorUser).ConfigureAwait(false); } } } // 其他原有方法保持不变 }
补充说明
如果后续需要在自定义的OnOriginChanged事件中传递更多参数,直接修改TestDataChangeEventArgs类增加对应属性即可,触发事件时赋值就能在订阅端拿到。
内容的提问来源于stack exchange,提问作者jon.r
相关产品推荐
相关产品推荐

