You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLDependency持续触发NewMessage事件问题求助

SQLDependency持续触发事件的问题

我开发C# WPF应用时,需要在特定表发生更新时通知其他PC上的用户,于是采用了SQLDependency。按照文档说明,它应该在数据变更时发送通知,但运行项目时NewMessage事件被持续触发。想知道是遗漏了配置,还是这是预期行为?有没有办法仅在关联表发生更新时获取通知?

实现的相关代码

SQLNotifier类

public class SQLNotifier : IDisposable
{
    public string ConnectionString
    {
        get
        {
            return Tools.LocalConnection;
        }
    }
    public SqlCommand CurrentCommand { get; set; }
    private SqlConnection connection;
    public SqlConnection CurrentConnection
    {
        get
        {
            this.connection = this.connection ?? new SqlConnection(this.ConnectionString.Replace("App=EntityFramework", ""));
            return this.connection;
        }
    }

    public SQLNotifier()
    {
        SqlDependency.Start(this.ConnectionString);
    }

    private event EventHandler<SqlNotificationEventArgs> _newMessage;

    public event EventHandler<SqlNotificationEventArgs> NewMessage
    {
        add
        {
            this._newMessage += value;
        }
        remove
        {
            this._newMessage -= value;
        }
    }

    public virtual void OnNewMessage(SqlNotificationEventArgs notification)
    {
        if (this._newMessage != null)
            this._newMessage(this, notification);
    }
    public DataTable RegisterDependency()
    {
        this.CurrentCommand = new SqlCommand("SELECT " +
            "Select_PractitionerID " +
            "FROM " +
            "CurrentSelection " +
            "WHERE " +
            "Select_PractitionerID = @PracID AND " +
            "Select_PCName <> @PCName AND Select_Location IS NOT NULL",
            this.CurrentConnection);

        this.CurrentCommand.Notification = null;
        CurrentCommand.Parameters.AddWithValue("@PracID", Tools.CurrentPrat.Prac_ID);
        CurrentCommand.Parameters.AddWithValue("@PCName", Tools.PCName);

        SqlDependency dependency = new SqlDependency(this.CurrentCommand);
        
        dependency.OnChange += this.dependency_OnChange;

        if (this.CurrentConnection.State == ConnectionState.Closed)
            this.CurrentConnection.Open();
        try
        {
            DataTable dt = new DataTable();
            dt.Load(this.CurrentCommand.ExecuteReader(CommandBehavior.CloseConnection));
            return dt;
        }
        catch (Exception ex)
        {
            return null;
        }
    }

    void dependency_OnChange(object sender, SqlNotificationEventArgs e)
    {
        SqlDependency dependency = sender as SqlDependency;

        dependency.OnChange -= new OnChangeEventHandler(dependency_OnChange);

        this.OnNewMessage(e);
    }


    #region IDisposable Members

    public void Dispose()
    {
        SqlDependency.Stop(this.ConnectionString);
    }

    #endregion
}

用户控件中的调用

Notifier = new SQLNotifier();
Notifier.NewMessage += new EventHandler<SqlNotificationEventArgs>(notifier_NewMessage);
DataTable dt = Notifier.RegisterDependency();

事件处理方法

void notifier_NewMessage(object sender, SqlNotificationEventArgs e)
{
    // 这里持续收到通知
   ...
}

问题原因及解决办法

1. 查询语句不符合SQLDependency要求

SQLDependency对查询有严格的确定性要求,你的查询中使用了<>(不等于)运算符,且表名未指定架构(如dbo.),这可能导致通知异常触发。

  • 修改查询,指定完整表名(比如dbo.CurrentSelection)
  • 确保查询仅包含明确列名,无聚合、子查询等禁止内容
  • 尽量避免非确定性运算符,若业务需要保留不等于逻辑,可确认语法符合SQL Server查询通知的规范

2. 未重新注册依赖

SQLDependency是一次性的,触发一次后就会失效。当前代码在事件触发后仅移除了事件绑定,未重新注册依赖,这会导致异常重复通知。修改dependency_OnChange方法:

void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
    SqlDependency dependency = sender as SqlDependency;
    dependency.OnChange -= dependency_OnChange;

    // 重新注册依赖,确保后续能接收新的更新通知
    this.RegisterDependency();

    this.OnNewMessage(e);
}

3. 检查SQL Server Service Broker配置

确保目标数据库已启用Service Broker:

-- 检查状态
SELECT name, is_broker_enabled FROM sys.databases WHERE name = '你的数据库名';

-- 启用Service Broker(若未启用)
ALTER DATABASE 你的数据库名 SET ENABLE_BROKER;

4. 过滤有效通知

在事件处理方法中,通过SqlNotificationEventArgs的属性过滤仅处理实际数据更新的通知:

void notifier_NewMessage(object sender, SqlNotificationEventArgs e)
{
    // 只处理数据变更的通知,忽略订阅失效、错误等情况
    if (e.Type == SqlNotificationType.Change && e.Info == SqlNotificationInfo.Update)
    {
        // 执行你的业务逻辑
    }
}

5. 确认权限

确保连接字符串的数据库用户拥有SUBSCRIBE QUERY NOTIFICATIONS权限,以及目标表的SELECT权限。


内容的提问来源于stack exchange,提问作者Coskun Ozogul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 23:30:45