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

如何结合SQL Broker与SignalR实现按企业过滤推送更新?

如何结合SQL Broker与SignalR实现多企业的实时数据更新通知

首先纠正你的一个理解偏差:SQL Broker 可以捕获并传递变更的具体内容(比如被更新的企业ID),完全不需要为每个企业单独建表。下面是具体的落地思路:

一、让SQL Broker携带企业标识发送变更消息

你可以通过变更数据捕获(CDC)或者触发器+Service Broker队列的组合,在捕获数据变更时,把受影响行的CompanyId(企业标识)打包进消息里,传给Web服务器:

  • 举个触发器的简化例子(假设你的主表是PersonStatus,包含CompanyId字段):
    CREATE TRIGGER trg_PersonStatus_Change ON PersonStatus
    AFTER INSERT, UPDATE, DELETE
    AS
    BEGIN
        SET NOCOUNT ON;
        -- 打包变更的企业ID和操作类型为JSON
        DECLARE @Msg NVARCHAR(MAX) = (
            SELECT 
                CompanyId,
                Operation = CASE 
                    WHEN EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted) THEN 'UPDATE'
                    WHEN EXISTS(SELECT * FROM inserted) THEN 'INSERT'
                    ELSE 'DELETE'
                END
            FROM inserted 
            UNION ALL
            SELECT CompanyId, 'DELETE' FROM deleted
            FOR JSON AUTO
        );
    
        -- 发送消息到Service Broker队列
        DECLARE @DlgHandle UNIQUEIDENTIFIER;
        BEGIN DIALOG @DlgHandle
            FROM SERVICE [ChangeNotificationService]
            TO SERVICE 'ChangeNotificationServiceTarget'
            ON CONTRACT [ChangeNotificationContract]
            WITH ENCRYPTION = OFF;
    
        SEND ON CONVERSATION @DlgHandle MESSAGE TYPE [ChangeNotificationMsg] (@Msg);
        END CONVERSATION @DlgHandle;
    END
    

二、Web端联动SignalR实现精准推送

  1. SignalR分组配置:
    客户端连接时,根据用户所属的企业ID,自动加入对应的SignalR分组(比如直接用Company_{CompanyId}作为组名):

    public class StatusHub : Hub
    {
        // 客户端调用此方法加入对应企业分组
        public async Task JoinCompanyGroup(int companyId)
        {
            await Groups.AddToGroupAsync(Context.ConnectionId, $"Company_{companyId}");
        }
    }
    
  2. 后台监听SQL Broker并推送:
    在Web应用中用后台服务(比如ASP.NET Core的IHostedService)监听SQL Broker的队列,收到消息后解析出CompanyId,然后调用SignalR Hub向对应分组发通知:

    public class ChangeNotificationService : BackgroundService
    {
        private readonly IHubContext<StatusHub> _hubContext;
        // 省略SQL Broker连接初始化代码
    
        public ChangeNotificationService(IHubContext<StatusHub> hubContext)
        {
            _hubContext = hubContext;
        }
    
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                // 从SQL Broker队列接收消息
                var message = await ReceiveBrokerMessage(stoppingToken);
                if (!string.IsNullOrEmpty(message))
                {
                    var changeEvents = JsonSerializer.Deserialize<List<ChangeEvent>>(message);
                    // 去重,避免重复推送同一企业的变更
                    var targetCompanies = changeEvents.Select(e => e.CompanyId).Distinct();
                    
                    foreach (var companyId in targetCompanies)
                    {
                        // 只通知对应企业的客户端
                        await _hubContext.Clients.Group($"Company_{companyId}")
                            .SendAsync("RefreshStatusData", stoppingToken);
                    }
                }
                await Task.Delay(100, stoppingToken);
            }
        }
    
        // 自定义类,对应SQL消息的结构
        private class ChangeEvent
        {
            public int CompanyId { get; set; }
            public string Operation { get; set; }
        }
    }
    

三、备选:分表场景(不推荐)

如果出于业务强隔离或极端性能需求要给每个企业单独建表(比如PersonStatus_Company1),可以为每个表单独配置SQL Broker队列,后台服务监听所有队列,收到对应表的消息后直接通知该企业的分组。但这种方案会大幅增加维护成本,除非必要,优先用单表+企业ID的方案。

关键注意事项

  • 做好SQL Broker的消息可靠性处理:比如失败重试、死信队列,避免丢失变更通知。
  • SignalR分组要及时清理:用户切换企业或断开连接时,从旧分组移除,避免无效推送。
  • 批量处理高频变更:短时间内大量变更时,合并同一企业的推送请求,防止SignalR过载。

内容的提问来源于stack exchange,提问作者Torbjörn Andersson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 19:20:16