在SQL Table Dependency中将多次更新合并为单次OnChange事件触发
批量操作下TableDependency事件合并处理方案
问题背景
现有代码可正常监听SQL Server表变更并通过SignalR推送,但遇到单次100条以上的批量插入/更新时,OnChanged事件会多次触发。需要合并这些触发动作,仅保留每条记录的最后一次更新数据后再推送。
原运行代码:
private void TableDependency_OnChanged(object sender, System.EventArgs e) { if (((TableDependency.SqlClient.Base.EventArgs.RecordChangedEventArgs <TestTable>)e).ChangeType.ToString() != "Delete") { string name = e.Entity.Name; int id = e.Entity.ID; SignalRTestHub.SendAllItemsAsync(id,name); } }
解决思路
采用本地缓存+延迟触发的方式处理:
- 用字典缓存每个ID的最新变更数据,自动覆盖旧记录
- 用定时器延迟执行推送,确保批量操作的所有变更都被捕获后,一次性推送所有缓存的最新数据
- 推送完成后清空缓存,避免重复推送
实现代码
1. 定义类级别的缓存与定时器
// 缓存每个ID的最新数据,key为TestTable的ID,value为对应Name private readonly Dictionary<int, string> _latestRecords = new Dictionary<int, string>(); // 延迟推送定时器,时长可根据批量操作实际耗时调整,示例设为500ms private readonly System.Timers.Timer _delayTimer = new System.Timers.Timer(500); // 线程安全锁,避免并发访问字典时出错 private readonly object _lockObj = new object(); // 在类的构造函数中初始化定时器 public YourClass() { _delayTimer.AutoReset = false; // 仅触发一次,防止重复执行 _delayTimer.Elapsed += DelayTimer_Elapsed; }
2. 修改OnChanged事件处理逻辑
private void TableDependency_OnChanged(object sender, System.EventArgs e) { var args = (TableDependency.SqlClient.Base.EventArgs.RecordChangedEventArgs<TestTable>)e; if (args.ChangeType.ToString() == "Delete") return; lock (_lockObj) { // 缓存最新数据,存在则覆盖,不存在则添加 if (_latestRecords.ContainsKey(args.Entity.ID)) { _latestRecords[args.Entity.ID] = args.Entity.Name; } else { _latestRecords.Add(args.Entity.ID, args.Entity.Name); } } // 重置定时器:如果之前已启动,先停止再重新计时,确保最后一次变更后再等待指定时长才推送 _delayTimer.Stop(); _delayTimer.Start(); }
3. 实现定时器触发后的批量推送逻辑
private void DelayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { Dictionary<int, string> recordsToSend; lock (_lockObj) { // 复制缓存数据并清空原缓存,避免后续变更干扰当前推送 recordsToSend = new Dictionary<int, string>(_latestRecords); _latestRecords.Clear(); } // 批量推送所有最新数据 foreach (var record in recordsToSend) { SignalRTestHub.SendAllItemsAsync(record.Key, record.Value).Wait(); // 若SignalR支持批量推送接口,可改为单次调用提升效率: // SignalRTestHub.SendBatchItemsAsync(recordsToSend).Wait(); } }
注意事项
- 定时器延迟时长需根据业务实际调整,确保能覆盖批量操作的全部执行时间
- 必须加锁,因为
OnChanged事件可能由多线程触发,避免字典并发访问异常 - 如需处理删除事件,可在
OnChanged中单独分支处理,比如从缓存移除对应ID或直接推送删除通知
内容的提问来源于stack exchange,提问作者Code
相关产品推荐
相关产品推荐

