2013-03-22 268 views
3

這是我第一次需要使用SqlDependency,所以我希望它是我犯的一個愚蠢的錯誤。SqlDependency OnChange沒有觸發

我遇到的問題是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特性的一個子集可以在依賴中使用,但我不認爲我想在這裏做任何事情。

+0

認爲任何人試圖尋找sqldependency的解決方法,應使用sqldependencyEx。簡單的連接步驟可以在這裏找到。 https://github.com/dyatchenko/ServiceBrokerListener – kepung 2017-04-19 22:41:21

回答

19

我希望它是我犯的一個愚蠢的錯誤。

不幸的是(或幸運的是)你犯了幾個錯誤。

  1. 首先是你要明白,查詢通知將失效一個查詢。因此,如果您想收到進一步的通知,您將只會收到最多一次的通知,並且您必須重新訂閱(重新提交查詢)。

  2. 接下來你需要了解的是,你將被通知任何的原因,不僅僅是因爲改變。在您的回撥中,您需要必須檢查您通知的原因,通過SqlNotificationEventArgs傳入。

  3. 接下來,您需要了解異步編程的基本原則:如果您訂閱活動,請確保您訂閱之前活動可能會首次發生。例如:On_SqlBitChanged只要提交查詢即可激發。這個應該發生在SqlWatcher.SqlWatcher構造函數中,但是你在構造函數運行後訂閱了sqlWatcher.NewMessage。在掛鉤NewMessage事件回調之前,可以在構造函數完成之間調用On_SqlBitChanged,在這種情況下,通知會被靜默忽略。

  4. 如果您想使用服務,請確保在使用之前啓動它。您在SqlWatcher.SqlWatcher中使用SqlDependency,但在之後啓動它,即當您撥打SqlWatcher.Start()時。

  5. 最後,如果您想要收到關於查詢更改的通知,則必須提交查詢。您正在構建SqlCommand對象,設置通知,然後...放棄該對象。除非您確實提交了查詢,否則您尚未訂閱任何東西

建議的解決辦法:

  • StartStop靜,叫Start在應用程序啓動。
  • 確保您之前訂閱NewMessage您提交的查詢
  • 其實提交查詢(調用SqlComamnd.ExecuteQuery()
  • 檢查在On_SqlBitChanged回調InfoTypeSource,如果您提交包含一個錯誤,這是學習的唯一方法(即使通知請求無效,SqlComamnd.ExecuteQuery()也會成功)
  • 您必須重新訂閱,一旦通知您有更改,請再次執行查詢。

還有一件事:不要在背景回調中調用UI代碼。您不能通過回撥呼叫MessageBox.Show("Message Received");,您必須通過Form.Invoke路由表單主線程。嗯,我知道嚴格來說MessageBox.Show確實工作在非UI線程上,但是你很快就會離開警報箱來實際形成交互,然後事情就會中斷。