在我们的应用程序中,当使用同一应用程序的其他任何用户更改特定建筑物的这些字段时,我们需要实时更新建筑物的某些字段(即,是否已被占用)。
但是,仅当两个用户当前都在查看同一建筑物时,才需要这样做。在网格中选择了建筑物,因此当更改选定的行时,我将使用正确的SqlCommand创建一个新的SqlDependency对象。
RefreshDependency方法:
private void RefreshDependency()
{
if (//Check if a row is selected at all and if it's a valid building)
{
if (_dependency != null)
{
_dependency.OnChange -= OnDependencyChange;
}
using (SqlConnection connection = new SqlConnection(_connectionString))
{
if (connection.State == ConnectionState.Closed)
{
connection.Open();
}
using (SqlCommand command = new SqlCommand($"SELECT [MyFields] FROM [dbo.MyTable] WHERE [BuildingID] = '{selectedBuilding.ID}'", connection))
{
SqlDependency dependency = new SqlDependency(command);
_dependency = dependency;
dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);
using (SqlDataReader reader = command.ExecuteReader())
{
reader.Read();
}
}
connection.Close();
}
}
}
OnDependencyChange事件:
private void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
RefreshDependency();
//Code to update fields
}
由于并非总是调用OnChange事件,因此在重新分配它之前,我会在每次调用RefreshDependency时都将其移除,而不是在OnChange事件本身内部进行移除。
现在的问题是,尽管代码运行正常并且只要数据库中发生更改,应用程序就可以正确更新,但在调查由SqlDependency引起的内存泄漏问题时,我注意到每次创建新的SqlDependency时,它都会创建sys.conversation_endpoints中的新对话。到目前为止还可以,但是如果用户碰巧长时间保持其概览处于打开状态并选择说在几个小时内完成100座建筑物,则将100个新对话添加到sys.conversation_endpoints中。但是,只有收到更改的用户才会被设置为CLOSED,其余的将保留在STARTED_OUTBOUND上,使用寿命非常长。
现在,我可以清理掉已关闭的会话,但是我不认为我可以对STARTED_OUTBOUND做同样的事情,以免删除实际上仍然需要对其他用户开放的对话,对吗?由于每个人自然共享一个数据库。
我不确定这完全不是我的代码存在的问题,因为即使只创建了一个依赖关系,也没有人对该建筑物进行任何更改,并且用户只是关闭了应用程序或概述(导致SqlDependency。 Stop()被调用),这也会使一次对话也停留在STARTED_OUTBOUND上。
我注意到,即使字段更改了很多,很久以后,数据库也会将所有相关的对话也关闭,无论它们是多久以前创建的,但是考虑到多个建筑物可能永远都不会收到更改,我有点担心不检查这些对话-我知道CLOSED对话被认为是内存泄漏,并且已经为这些对话实施了修复。
如果这是为SqlDependency设计的,我应该考虑使用SqlDependencyEx或SqlTableDependency之类的替代方法吗?