我终于有了大量功能失调的例子,设法在SqlDependency
对象上收到更改消息。这些知识可能会让您为我的代码的不雅或不正确做好准备。
我有一个ActiveList<T>: ObservableCollection<T>
类,用于侦听对其数据库表数据源的更改并重新填充自身。我使用以下代码创建并初始化列表和SqlDependency
:
构造
public ActiveList()
{
PopulateList();
}
填充:
private void PopulateList()
{ Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, ((Action)(() =>
{
Clear();
using (var dbContext = new XTimeDbContext())
{
var set = dbContext.Set<T>().ToList();
this.AddRange(set);
}
})));
SubscribeNotifications();
}
订阅:
private void SubscribeNotifications()
{
const string dependencyQuery = "select TITLE_ACTIVE, TITLE_NAME from dbo.TITLE";
var dependency = new SqlDependency();
dependency.OnChange += DependencyOnChange;
var connectionString = _dbContext.Database.Connection.ConnectionString;
//SqlDependency.Stop(connectionString);
SqlDependency.Start(connectionString);
using (var sqn = new SqlConnection(connectionString))
{
sqn.Open();
using (var cmd = new SqlCommand(dependencyQuery, sqn))
{
cmd.Notification = null;
dependency.AddCommandDependency(cmd);
//dependency.OnChange += DependencyOnChange;
using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
}
}
}
}
}
最后,请听:
private void DependencyOnChange(object sender, SqlNotificationEventArgs sqlNotificationEventArgs)
{
_trace.TraceInformation("DependencyOnChange called. Reason: '{0}', Source: '{1}', Type: '{2}'.", sqlNotificationEventArgs.Info, sqlNotificationEventArgs.Source,
sqlNotificationEventArgs.Type);
//if (!_isPopulating)
//{
// PopulateList();
//}
SqlDependency.Stop(_dbContext.Database.Connection.ConnectionString;);
SubscribeNotifications();
_trace.TraceInformation("DependencyOnChange completed.");
}
由于大量小的实验性更改,代码处于轻微混乱状态,但我的主要问题是,当我运行使用ActiveList
的测试应用时,我会收到第一个更改通知;我的日志显示“DependencyOnChange called”。然后,对SqlDependency.Stop
的调用,无论我放在哪里,都会生成InvalidOperationException
,并显示消息:
There is already an open DataReader associated with this Command which must be closed first.
我在代码中的任何地方都找不到'悬空'数据读取器,那么可能导致这种情况发生了什么?
答案 0 :(得分:0)
也许只是一种解决方法......但您是否尝试在连接上将MultipleActiveResultSets设置为true?
答案 1 :(得分:0)
您应该在开始时只调用一次SqlDependency.Start(connectionString);
,在结束时调用SqlDependency.Stop(_dbContext.Database.Connection.ConnectionString;);
一次(当您决定不进行更改时)。这些命令为更改事件创建和删除队列。
只要您需要订阅下一次更改,就应该调用下一行。
var dependency = new SqlDependency();
dependency.OnChange += DependencyOnChange;
例如:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
SqlDependency.Start("server=<MyServer>;database=<MyDB>;User ID=<user>;Password=<pwd>;Integrated Security=false;");
Console.WriteLine("Started..");
get_msg();
Console.ReadLine();
SqlDependency.Stop("server=<MyServer>;database=<MyDB>;User ID=<user>;Password=<pwd>;Integrated Security=false;");
}
private static void get_msg()
{
using (SqlConnection con =
new SqlConnection("server=<MyServer>;database=<MyDB>;User ID=<user>;Password=<pwd>;Integrated Security=false;"))
{
SqlCommand com = new SqlCommand("SELECT MyTableID, SomeText FROM dbo.MyTable ", con);
SqlDependency dependency = new SqlDependency(com);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
con.Open();
com.ExecuteNonQuery();
}
}
static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
Console.WriteLine("dependency Info = {0}, time: {1}",e.Info, DateTime.Now);
get_msg();
}
}
}
请记住,SQL依赖关系适用于DB中的更改不频繁的情况。在代码示例中,下一次更改的订阅是即时的,但是等待一段时间是个好主意。