这是我第一次需要使用 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.
不幸的是(还是幸运的?)你犯了几个错误。
首先您需要了解查询通知将使一个查询无效。因此,您最多只会收到一次通知,如果您想收到更多通知,则必须重新订阅(重新提交查询)。
接下来您需要了解您会因任何原因而收到通知,而不仅仅是更改。在您的回调中,您必须检查您收到通知的原因,这是通过
SqlNotificationEventArgs
传入的。接下来您需要了解异步编程的基本原则:如果您订阅一个事件,请确保您在该事件第一次发生之前订阅。恰当的例子:
On_SqlBitChanged
可以在您提交查询后立即触发。这应该发生在SqlWatcher.SqlWatcher
构造函数中,但是您订阅了sqlWatcher.NewMessage
在构造函数运行之后.On_SqlBitChanged
可以在连接NewMessage
事件回调之前在构造函数完成之间调用,在这种情况下通知将被静默忽略。如果您想使用服务,请确保在使用它之前启动它。您正在
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 线程上工作,但您很快就会从警告框转移到实际形成交互,然后事情就会崩溃.
关于c# - SqlDependency OnChange 未触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15566966/