【问题标题】:Make C# Dependency only trigger when new rows have been inserted into MS SQL with specific column value仅当具有特定列值的新行插入到 MS SQL 中时才触发 C# 依赖关系
【发布时间】:2019-08-16 14:46:54
【问题描述】:

当新行被插入到具有特定列值的 MS SQL 时,我想接收“更改”事件。

下面是我目前使用的代码,效果相当不错,只是它会在 [Status] 列中的任何行值更改为/或从“NEW”时触发事件。

public void InitialiseDependencyWORK(Action onDependencyMethod)
{

    this.onDependencyMethod = onDependencyMethod;

    string sqlCommandText = "SELECT [Symbol] FROM [JJ].[Orders] WHERE [Status] = 'NEW'";

    using (SqlCommand command = new SqlCommand(sqlCommandText, conn))
    {

        Dependency = new SqlDependency(command);

        Dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);

        using (SqlDataReader reader = command.ExecuteReader())
        {
            // Process the DataReader.
        }
    }

}

void OnDependencyChange(object sender,
   SqlNotificationEventArgs e)
{
    // Handles NEW rows
}

我只对使用 [Status] = "NEW" 插入新行感兴趣,但是当没有新插入但 [Status] 从“NEW”更改为其他任何内容时也会触发此事件。

如何只在有新插入时才获得触发事件?

我希望在插入新闻行时收到触发事件,如下面的第 2 行:

OrderID, Status 
1,Done 
2,NEW 

我不希望它触发,因为第 2 行的状态刚刚更新 - 实际上没有要处理的新行:

OrderID, Status
1,Done
2,Done

我怎样才能做到这一点?

【问题讨论】:

  • 为什么要删除旧的Question 并复制它?这不会对您之前的问题添加任何内容。
  • 问题重组以更好地解释我的问题
  • 您可以使用if(e.Info == "Insert") 专门检查您的处理程序中的插入,忽略其他并重新订阅。
  • @DanGuzman 如果有大量更新和更改,e.Info 会返回什么?

标签: c# sql-server dependencies


【解决方案1】:

我认为只要表中有任何插入/更新/删除,就会触发 SqlDependency 事件。

没有办法阻止它。

您可以在事件中捕获适当的通知类型并且您是否工作。

void OnDependencyChange(object sender,
   SqlNotificationEventArgs e)
{
    if (e.Info == SqlNotificationInfo.Insert)
}

我没有尝试过的其他方法,

创建另一个表OrdersCopy,它是[JJ].[Orders]的副本

在订单表中创建插入触发器。

只要订单表中有插入,触发器就会触发。 在OrdersCopy中插入新记录

这里做如下改动,将表名改为OrderCopy

string sqlCommandText = "SELECT [Symbol] FROM [JJ].[OrdersCopy] WHERE [Status] = 'NEW'";

对于实验摇晃,您可以尝试一次。

OnDependencyChange 事件只会在插入的情况下触发。

【讨论】:

    【解决方案2】:

    使用SqlDependency 的一般用例是检测对您希望缓存的不经常更改的数据的更改,但还需要知道它是否确实更改,以便您无需轮询即可刷新缓存数据库。您的情况略有不同,因为您真的不想知道该查询的结果何时更改……您想知道某个查询何时包含要处理的结果。当状态代码从“NEW”更改为 AND 时您收到通知的原因是因为这两种类型的更改都会改变查询结果。它是根据这两种变化来加减整行。

    如果您只使用状态代码“NEW”和“DONE”,并且保证它们始终以“NEW”启动并且只前进到“DONE”(并且永远不会返回),那么解决方法可能是使用这个查询:

    SELECT [OrderID] FROM [JJ].[Orders] WHERE [Status] <= 'NEW'
    

    这样,在状态“NEW”中添加的新项目将更改查询结果...但是当它移动到“DONE”时,它仍将是查询中返回的OrderID,并且不应触发更改事件。如果你有更多的状态值,你会进步......你可以考虑在你的状态栏中使用一个整数来表示进步。例如 0 表示新的,1 表示进行中,2 完成......等等。

    听起来您正在尝试创建某种要完成的工作队列,并且还有其他方法可以做这种事情。有 SQL Server 更改跟踪和数据更改跟踪、触发器、Service Broker 队列和许多其他队列技术。您可以查看它们以及您的架构的选项。

    【讨论】:

      【解决方案3】:

      请问您为什么要在 c# 中为上下文重新发明 SQL 触发器? https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-2017

      最简单的解决方案是在表本身而不是通过会产生误报的查询来捕获它。

      或者,如果您通过存储库层运行所有代码,那么您应该能够区分 INSERT 和 UPDATE 并在那里选择它。

      【讨论】:

      • 不知道你所说的重生是什么意思。我正在使用 c# 功能在我的 c# 应用程序中接收事件触发器,因为它是想要对插入事件执行某些操作的应用程序。我可以使用您的建议来实现这一目标吗?
      • 抱歉,ManInMoon 回复延迟。如果唯一可能的编辑路径是通过您的应用程序,并且您有一个业务逻辑层或存储库模式,其中所有编辑都通过该单点运行,您可以在它们发生之前抢先确定编辑,如前所述。这对我来说是粗略的,因为您锁定了您将只允许通过该单点进行更改的想法。这当然是理想的,但您必须确保对该数据的所有编辑仅通过该单点进行。在表格级别,您可以确保捕获它。
      猜你喜欢
      • 2016-11-16
      • 2020-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-30
      • 2010-11-14
      • 2018-12-29
      相关资源
      最近更新 更多