c# - 从 TableDependency 优雅地处理数万个事件 C#

标签 c# sql events entity-framework-core event-handling

我有一个项目,其中一部分监控对 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/

相关文章:

c# - 如何在 c# 中获取邮件事件,如阅读、删除、回复、转发邮件

jquery - 如何通过从 $.ajax() 检索的 DOM 访问元素?

c# - 使用base()有意义吗?

c# - Jquery 下拉列表值返回未定义

c# - 删除单个反斜杠,将字符串中的 double 转换为单精度数

sql - 如何在 postgresql 中获取唯一约束的名称?

php - 使用子字符串 PHP 在页面上显示 SQL 表中的 "Date"数据类型

sql - 如何知道某列中所有单元格是否具有相同的值

java - 如何为relativeLayout设置OnTouchListener?

javascript - formaction、formmethod、formenctype通过jQuery提交