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

在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 08:00:08