如何结合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实现精准推送
SignalR分组配置:
客户端连接时,根据用户所属的企业ID,自动加入对应的SignalR分组(比如直接用Company_{CompanyId}作为组名):public class StatusHub : Hub { // 客户端调用此方法加入对应企业分组 public async Task JoinCompanyGroup(int companyId) { await Groups.AddToGroupAsync(Context.ConnectionId, $"Company_{companyId}"); } }后台监听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
相关产品推荐
相关产品推荐

