c# - SqlDependency OnChange 未触发

标签 c# sql sql-server sqldependency

这是我第一次需要使用 SqlDependency,所以我希望这是我犯的一个愚蠢的错误。

我遇到的问题是 OnChanged 事件不会在 sql 表更改时触发。没有错误或任何它不会触发的东西。

这是代码

public class SqlWatcher
{
    private const string SqlConnectionString = "Data Source = CN-PC08\\DEV; Initial Catalog=DEP; User = sa; Password=******";

    public SqlWatcher()
    {
        SqlClientPermission perm = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
        perm.Demand();

        SqlCommand cmd = new SqlCommand("SELECT [DataAvaliable], [RowNumber] FROM [dbo].[Trigger]", new SqlConnection(SqlConnectionString));
        SqlDependency sqlDependency = new SqlDependency(cmd);
        sqlDependency.OnChange += On_SqlBitChanged;
    }

    private void On_SqlBitChanged(object sender, SqlNotificationEventArgs sqlNotificationEventArgs)
    {
        SqlDependency dependency = (SqlDependency)sender;
        dependency.OnChange -= On_SqlBitChanged;

        // Fire the event
        if (NewMessage != null)
        {
            NewMessage(this, new EventArgs());
        }
    }

    public void Start()
    {
        SqlDependency.Start(SqlConnectionString);
    }

    public void Stop()
    {
        SqlDependency.Stop(SqlConnectionString);
    }

    public event EventHandler NewMessage;

在我的主窗口中有这个

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        try
        {
            SqlWatcher sqlWatcher = new SqlWatcher();
            sqlWatcher.Start();
            sqlWatcher.NewMessage += On_NewMessage;
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

    private void On_NewMessage(object sender, EventArgs eventArgs)
    {
        MessageBox.Show("Message Received");
    }
}

所以预期的行为是,如果我运行以下 sqlQuery,将显示一个消息框,上面写着“消息已收到”

INSERT INTO [DEP].[dbo].[Trigger] Values(0,3)

任何人都可以提示我要检查/更改的内容吗?

我知道在依赖项中只能使用 Sql 功能的一个子集,但我不认为我想在这里做任何花哨的事情。

最佳答案

I'm hoping that its a stupid mistake I've made.

不幸的是(还是幸运的?)你犯了几个错误。

  1. 首先您需要了解查询通知将使一个查询无效。因此,您最多只会收到一次通知,如果您想收到更多通知,则必须重新订阅(重新提交查询)。

  2. 接下来您需要了解您会因任何原因而收到通知,而不仅仅是更改。在您的回调中,您必须检查您收到通知的原因,这是通过 SqlNotificationEventArgs 传入的。

  3. 接下来您需要了解异步编程的基本原则:如果您订阅一个事件,请确保您在该事件第一次发生之前订阅。恰当的例子:On_SqlBitChanged 可以在您提交查询后立即触发。这应该发生在 SqlWatcher.SqlWatcher 构造函数中,但是您订阅了 sqlWatcher.NewMessage构造函数运行之后. On_SqlBitChanged 可以在连接 NewMessage 事件回调之前在构造函数完成之间调用,在这种情况下通知将被静默忽略。

  4. 如果您想使用服务,请确保在使用它之前启动它。您正在 SqlWatcher.SqlWatcher 中使用 SqlDependency,但是您在 之后 调用 SqlWatcher.Start() 时启动了它。

  5. 最后,如果您希望收到有关查询更改的通知,您必须提交查询。您正在构建 SqlCommand 对象,设置通知,然后……丢弃该对象。除非您实际提交查询,否则您还没有订阅任何内容

修复建议:

  • 使StartStop静态化,在应用程序启动时调用Start
  • 在提交查询之前,确保您订阅了 NewMessage
  • 实际提交查询(调用SqlComamnd.ExecuteQuery())
  • 检查 On_SqlBitChanged 回调中的 InfoTypeSource,如果您的提交包含此错误是唯一的学习方法(即使通知请求无效,SqlComamnd.ExecuteQuery() 也会成功)
  • 一旦收到更改通知,您必须重新订阅,再次执行查询。

还有一件事:不要在后台回调中调用 UI 代码。您不能从回调中调用 MessageBox.Show("Message Received");,您必须通过 Form.Invoke 路由到表单主线程.是的,我知道严格来说 MessageBox.Show 确实 在非 UI 线程上工作,但您很快就会从警告框转移到实际形成交互,然后事情就会崩溃.

关于c# - SqlDependency OnChange 未触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15566966/

相关文章:

sql - SAP B1 中如何生成唯一 ID/序列号?

sql - CONTEXT_INFO() 和转换

c# - 行尾有空白

c# - 在 C# 中使用 libtiff 从一种 TIFF 格式转换为另一种

python - SqlAlchemy:如何在 where 子句中使用选定子查询的结果

sql - 如何改进具有多个外键但实际上每次只使用其中一个键的表设计?

sql-server - Windows 管理员没有 SQL Server 的权限

python - 执行 Sql 脚本返回 "None"

c# - 如果包含特定单词,则替换整行的正则表达式

c# - 在已实现的接口(interface)属性上强制使用私有(private)访问修饰符的解决方法