SqlDependency OnChange未触发
这是我第一次需要使用SqlDependency,所以我希望这是我犯的一个愚蠢的错误。
我遇到的问题是当sql表更改时,OnChanged事件不会触发。 没有错误或任何事情只是它不会触发。
这是代码
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)
任何人都可以给我一个关于检查/更改内容的提示吗?
我知道只有一部分Sqlfunction可用于依赖项,但我认为我不想在这里做任何事情。
我希望这是我犯过的一个愚蠢的错误。
不幸的是(或幸运的是?)你犯了几个错误。
-
首先,您需要了解查询通知将使一个查询无效。 因此,您最多只会收到一次通知,如果您想再收到通知,则必须重新订阅(重新提交查询)。
-
接下来,您需要了解您将因任何原因得到通知,而不仅仅是更改。 在回调中,您必须检查通知的原因,这些原因通过
SqlNotificationEventArgs
传递。 -
接下来,您需要了解异步编程的基本原则:如果您订阅了一个事件,请确保在事件第一次发生之前订阅。
On_SqlBitChanged
:On_SqlBitChanged
可以在您提交查询后立即触发。 这应该发生在SqlWatcher.SqlWatcher
构造函数中,但是在构造函数运行后您订阅了sqlWatcher.NewMessage
。 在挂接NewMessage
事件回调之前,可以在构造函数完成之间调用On_SqlBitChanged
在这种情况下,将自动忽略通知。 -
如果要使用服务,请确保在使用之前启动它。 您正在
SqlWatcher.SqlWatcher
中使用SqlDependency,但是在您调用SqlWatcher.Start()
之后启动它。 -
最后,如果您希望收到有关查询更改的通知, 则必须提交查询 。 您正在构建
SqlCommand
对象,设置通知,然后…丢弃该对象。 除非您实际提交查询,否则您尚未订阅任何内容 。
修复建议:
-
Start
和Stop
静态,在应用程序启动时调用Start
。 - 确保在提交查询之前订阅
NewMessage
- 实际上提交查询(调用
SqlComamnd.ExecuteQuery()
) - 检查
On_SqlBitChanged
回调中的Info
,Type
和Source
,如果您的提交包含错误,这是学习的唯一方法(即使通知请求无效,SqlComamnd.ExecuteQuery()也会成功) - 一旦收到更改通知,您必须重新订阅,再次执行查询。
还有一件事:不要在后台回调中调用UI代码。 你不能调用MessageBox.Show("Message Received");
从回调中,您必须通过Form.Invoke
路由表单主线程。 是的,我知道严格来说MessageBox.Show
可以在非UI线程上工作,但你很快就会从警告框中移开来实际形成交互,然后事情就会破裂。