我有一个项目,其中一部分监控对 SQL 数据库所做的更改。我正在使用 SQL 表依赖项 NuGet 包来监视更改,以便在进行更改时更新 UI。
我遇到的问题是我的程序中有一个函数可以将 50-99k 行添加到数据库中的表中。事件被触发的次数与添加的行数一样多。这是有问题的,因为我不想将 UI 更新 99k 次。我最多想更新一次或两次。我现在的处理方式是,当我检测到在某个时间跨度内触发了 5 个事件时,我 DeInit TableDependency,然后延迟任务在几秒钟后重新启用它,并在最后触发 UI 更新,这样它就不会错过任何东西虽然它暂时被禁用了。
我还尝试使用静态 bool 来限制速率,而不是 DeIniting 和 ReIniting TableDependency,但有时需要 30-90 秒,因为事件处理程序无法合理地跟上它们。我认为 DeInit 工作得更好,因为从事件处理程序中删除回调似乎将其从事件中清除。否则我找不到从大量事件队列中清除事件处理程序的方法。
我尝试深入研究 Reactive Extensions 并使用 Throttle 函数。这工作正常,除了接收到的第一个事件不会触发。它会等到事件结束才触发(我意识到这是设计使然)。这会让程序暂时感觉没有响应,因为当事件被触发时,SQL 已经添加了所有行,所以它真正需要的是最多更新第一个事件和最后一个事件。
我试图寻找替代方案的原因是因为 TableDependency 有时(还不知道如何复制它)在具有无效 ID 的表上孤立 SQL 中的触发器脚本,并且当数据库实例(我我正在使用 EF6 核心)运行 SaveChanges()。我认为频繁运行 DeInit 和 Init 函数充其量对问题没有帮助,最坏的情况是它的直接原因。因此,我试图找到一些方法来避免频繁地 DeIniting 和 ReIniting TableDependency,同时让我的 UI 更新感觉响应迅速并且性能不差。
初始化函数:
private static void DeInitDependency(TableType tableType)
{
if(tableType == TableType.Event)
{
eventTableDependency.Stop();
eventTableDependency.Dispose();
eventTableDependency.OnChanged -= SqlDependencyEventTable_OnChanged;
eventTableDependency.OnError -= DepEvent_OnError;
eventTableDependency.OnStatusChanged -= DepEvent_OnStatusChanged;
eventChangeTrackingStarted = false;
}
else if (tableType == TableType.Location)
{
locationTableDependency.Stop();
locationTableDependency.Dispose();
locationTableDependency.OnChanged -= SqlDependencyLocationTable_OnChanged;
locationTableDependency.OnError -= DepLocation_OnError;
locationTableDependency.OnStatusChanged -= DepLocation_OnStatusChanged;
locationChangeTrackingStarted = false;
}
}
初始化/重新初始化函数:
public static void InitDependency(TableType tableType)
{
try
{
//Set Connection String to SQL
string dbConnectionString = "";
dbConnectionString = sqlCore.generateConnectionString();
if(tableType == TableType.Event)
{
//Create Dependency and Connect
eventTableDependency = new SqlTableDependency<NextGenGui.Models.Event>(dbConnectionString, executeUserPermissionCheck: false);
eventTableDependency.OnChanged += SqlDependencyEventTable_OnChanged;
eventTableDependency.OnError += DepEvent_OnError;
eventTableDependency.OnStatusChanged += DepEvent_OnStatusChanged;
eventTableDependency.Start();
eventChangeTrackingStarted = true;
Debug.WriteLine("Event SQL TRACKING STARTED!");
}
else if(tableType == TableType.Location)
{
locationTableDependency = new SqlTableDependency<Models.Location>(dbConnectionString, executeUserPermissionCheck: false);
locationTableDependency.OnChanged += SqlDependencyLocationTable_OnChanged;
locationTableDependency.OnError += DepLocation_OnError;
locationTableDependency.OnStatusChanged += DepLocation_OnStatusChanged;
locationTableDependency.Start();
locationChangeTrackingStarted = true;
Debug.WriteLine("Location SQL TRACKING STARTED!");
}
}catch (Exception ex)
{
Debug.WriteLine(ex);
if(ex.Message.Contains("Service broker"))
{
InitSQLBrokerSetting();
}
}
}
最佳答案
听起来好像每个业务级操作需要一个事件,而不是每个表更新一个事件。如果是这种情况,那么您将不得不考虑实现您自己的解决方案。 SignalR 和 ServiceBus 等主题是研究的良好起点。无论如何,这种业务操作流对于审计和缓存来说都是有用的。
值得指出的是,您不必一次性完全替换 SQL Table Dependency。您可以只从导致批量操作出现问题的表开始。
关于c# - 从 TableDependency 优雅地处理数万个事件 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73199114/