我有以下代码使用SqlDependency来监视我的一个数据库中的更改它运行良好,除了每次运行它在数据库中使用guid生成自己的队列/服务/路由:
类别:
class SqlWatcher
{
private string connectionString;
private string sqlQueue;
private string listenerQuery;
private SqlDependency dependency;
public SqlWatcher(string connectionString, string sqlQueue, string listenerQuery)
{
this.connectionString = connectionString;
this.sqlQueue = sqlQueue;
this.listenerQuery = listenerQuery;
this.dependency = null;
}
public void Start()
{
SqlDependency.Start(connectionString);
ListenForChanges();
}
public void Stop()
{
SqlDependency.Stop(this.connectionString);
}
private void ListenForChanges()
{
//Remove existing dependency, if necessary
if (dependency != null)
{
dependency.OnChange -= onDependencyChange;
dependency = null;
}
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
SqlCommand command = new SqlCommand(listenerQuery, connection);
dependency = new SqlDependency(command);
// Subscribe to the SqlDependency event.
dependency.OnChange += new OnChangeEventHandler(onDependencyChange);
SqlDependency.Start(connectionString);
command.ExecuteReader();
//Perform this action when SQL notifies of a change
performAction();
connection.Close();
}
private void onDependencyChange(Object o, SqlNotificationEventArgs args)
{
if ((args.Source.ToString() == "Data") || (args.Source.ToString() == "Timeout"))
{
Console.WriteLine(System.Environment.NewLine + "Refreshing data due to {0}", args.Source);
ListenForChanges();
}
else
{
Console.WriteLine(System.Environment.NewLine + "Data not refreshed due to unexpected SqlNotificationEventArgs: Source={0}, Info={1}, Type={2}", args.Source, args.Info, args.Type.ToString());
}
}
private void performAction()
{
Console.WriteLine("Performing action");
}
}
执行:
static void Main(string[] args)
{
string connectionString = @"<MY CONNECTION STRING>";
string sqlQueue = @"NamesQueue";
//Listener query restrictions: http://msdn.microsoft.com/en-us/library/aewzkxxh.aspx
string listenerQuery = "SELECT Value FROM dbo.Table WHERE Name = 'Test'";
SqlWatcher w = new SqlWatcher(connectionString, sqlQueue, listenerQuery);
w.Start();
Thread.Sleep(10000);
w.Stop();
}
我不是每次都生成自己的队列/服务/路由,而是想先创建它们然后告诉我的程序使用它们。
我继续在数据库中创建这些对象:
CREATE QUEUE NamesQueue;
CREATE SERVICE NamesService ON QUEUE NamesQueue;
CREATE ROUTE NamesRoute WITH SERVICE_NAME = 'NamesService', ADDRESS = 'LOCAL';
并修改了我的C#代码以使用此队列和服务:
...
SqlDependency.Start(connectionString, sqlQueue);
...
SqlDependency.Stop(this.connectionString, sqlQueue);
...
dependency = new SqlDependency(command, "service=NamesService;local database=<MY DB>", 0);
...
SqlDependency.Start(connectionString,sqlQueue);
...
进行这些代码更改会导致在运行代码时无法动态创建队列,但是我的代码不再有效,而且我的应用程序无法识别对我的表/查询所做的更改。
我花了好几天时间试图解决这个问题但没有成功,有人可以提供任何建议吗?感谢。
答案 0 :(得分:6)
想出来 - 错误发生在我的SQL CREATE语句中。我正在使用:
CREATE SERVICE NamesService ON QUEUE NamesQueue;
但根据http://technet.microsoft.com/en-us/library/ms190332.aspx,CREATE SERVICE命令需要采用contract_name参数,以便能够允许其他对话框定位正在创建的服务。
因此,使用下面的CREATE语句解决了我的问题:
CREATE SERVICE NamesService
ON QUEUE NamesQueue
([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]) ;
答案 1 :(得分:0)
小心使用SqlDependency类 - 它有problems内存泄漏。 Hovewer,您可以使用SqlDependency类的开源实现 - SqlDependencyEx。它使用数据库触发器和本机Service Broker通知来接收有关表更改的事件。这是一个用法示例:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
希望这有帮助。