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
相关产品推荐
相关产品推荐

