我已经编写了这个类来自动化SQLDependencys
public class DatabaseChangeAlert
{
private String connectionString;
private SqlConnection sc;
public event EventHandler<DatabaseChangedEvent> DatabaseChangeEvent;
private String tabelle;
private String query;
public DatabaseChangeAlert(String tabelle, String conString)
{
try
{
this.tabelle = tabelle;
this.sc = new SqlConnection(conString); ;//new SqlConnection(GlobalResources.ConnectionString);
this.connectionString = conString;
String sel = "";
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = "SELECT dbo.syscolumns.name AS Spaltenname " +
" FROM dbo.syscolumns INNER JOIN " +
" dbo.sysobjects ON dbo.syscolumns.id = dbo.sysobjects.id " +
" WHERE (dbo.sysobjects.xtype = 'U') and dbo.sysobjects.name='" + tabelle + "' ";
using (SqlDataReader sr = cmd.ExecuteReader())
{
while (sr.Read())
{
sel += "["+sr.GetString(0)+"],";
}
}
sel = sel.Substring(0, sel.Length - 1);
}
query = "SELECT " + sel + " from [dbo].[" + tabelle+"]";
}
catch (Exception ex) { }
}
~DatabaseChangeAlert()
{
if(connectionString!=null)
SqlDependency.Stop(connectionString);
}
public void start()
{
try
{
SqlDependency.Start(connectionString);
}
catch (Exception ex)
{
// log(ex)
}
try
{
startDependency();
}
catch (Exception ex)
{
// log(ex)
}
}
private void startDependency()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
using (SqlCommand command = new SqlCommand(query, sc))
{
sc.Open();
// Create a dependency and associate it with the SqlCommand.
SqlDependency dependency = new SqlDependency(command);
// Maintain the refence in a class member.
// Subscribe to the SqlDependency event.
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
// Execute the command.
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
}
}
sc.Close();
}
}
void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Info != SqlNotificationInfo.Invalid)
{
startDependency();
if (DatabaseChangeEvent != null)
{
DatabaseChangeEvent(this, new DatabaseChangedEvent(tabelle,e.Info));
}
}
}
public class DatabaseChangedEvent : EventArgs
{
public readonly String Tablename;
public readonly SqlNotificationInfo info;
public DatabaseChangedEvent(String tablename,SqlNotificationInfo info)
{
this.Tablename = tablename;
this.info = info;
}
}
}
在我的程序中我像这样使用这个类:
DatabaseChangeAlert alerttz = new DatabaseChangeAlert("table1", GlobalResources.ConnectionString);
alerttz.DatabaseChangeEvent += (e,d)=>{
MessageBox.Show("table1 changed");
};
alerttz.start();
DatabaseChangeAlert alert = new DatabaseChangeAlert("table2", GlobalResources.ConnectionString);
alert.DatabaseChangeEvent += (e, d) =>
{
MessageBox.Show("table2 changed");
};
alert.start();
现在我的问题是,当我在table2中更改任何内容时,我没有收到通知,但是当我对表1执行相同操作时,我会收到通知!
任何想法可能是什么问题? 我也试图只为table2承诺...但它保持不变。
答案 0 :(得分:1)
我重复了你的情况并写了unit test(TwoTablesNotificationTest),但没有找到任何东西。这对我来说可以。在这种情况下,如果某个DatabaseChangeAlert
实体的析构函数调用,您可以停止从SqlDependency接收通知,因为它有SqlDependency.Stop(connectionString)
指令。因此,您必须在每SqlDependency.Start
之后调用SqlDependency.Stop
以继续接收事件,但垃圾收集器会从并行线程自动调用析构函数,这可能会导致此效果。
我想警告你 - 小心使用SqlDependency类,因为它有memory leak problem。对于我的项目,我使用了SqlDependency的开源实现 - SqlDependencyEx。它非常易于使用:
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);
希望这有帮助。