2009-10-12 77 views
4

我創建了以下封裝在SQL依賴對象:的SqlDependency在ASP.NET

public class DependencyTracker 
    { 
     private SqlDependency _SQLDependency = null; 

     public string ConnectionString 
     { get; private set; } 

     public string CommandNotifier 
     { get; private set; } 

     public delegate void Refresh(); 
     public event Refresh OnRefresh; 

     public DependencyTracker(string connectionString, string commandNotifier) 
     { 
      ConnectionString = connectionString; 
      CommandNotifier = commandNotifier; 
     } 

     public void StartDependency() 
     { 
      SqlDependency.Start(ConnectionString); 
     } 

     public void StopDependency() 
     { 
      SqlDependency.Stop(ConnectionString); 
     } 

     public void TrackForChanges() 
     { 
      using (SqlConnection sqlConn = new SqlConnection(ConnectionString)) 
      { 
       sqlConn.Open(); 
       using (SqlCommand sqlCommand = new SqlCommand(CommandNotifier, sqlConn)) 
       { 
        sqlCommand.CommandType = CommandType.StoredProcedure; 
        _SQLDependency = new SqlDependency(sqlCommand); 
        _SQLDependency.OnChange += new OnChangeEventHandler(dependency_OnChange); 
        sqlCommand.ExecuteReader(); 
       } 
      } 
     } 

     void dependency_OnChange(object sender, SqlNotificationEventArgs e) 
     { 
      SqlDependency sqlDependency = (SqlDependency)sender; 
      sqlDependency.OnChange -= dependency_OnChange; 

      if (OnRefresh != null) 
      { 
       OnRefresh(); 
      } 
     } 

     public bool HasChanges 
     { 
      get 
      { 
       return _SQLDependency.HasChanges; 
      } 
     } 
    } 

它不是一個原創作品,它是基於this text.從我的倉庫我做了以下內容:

public bool Updatexxx(Ixxx xsxs) 
     { 
      try 
      { 
       SqlConnection sqlConn = new SqlConnection(_ConnectionString); 
       sqlConn.Open(); 
       ... 

       bool result = sqlComm.ExecuteNonQuery() == 1; 

       _ResetEvent.WaitOne(); 

       return result; 
      } 
      catch ... 
      catch ... 
     } 

回調是

public void RefreshData() 
     { 
      FindAllxxx(); 
      _ResetEvent.Set(); 
     } 

而且

public HashSet<Iddd> Finddadas() 
     { 
      DependencyTracker tracker = _Container.Resolve<DependencyTracker>("dada"); 
      UnityHashSet<IT24Route> hash = _Container.Resolve<UnityHashSet<dadas>>("Tdsadas"); 
      if (tracker.HasChanges || hash.Count == 0) 
      { 
       hash = new UnityHashSet<dsda>(_Container); 
       hash.ImportHashSet(FindAlldsdsNonCached()); 
       _Container.RegisterInstance<UnityHashSet<dsds>>("dasda", hash); 
       tracker.TrackForChanges(); 
      } 
      return hash; 
     } 

和FindAllXXXNonCached()從數據庫中進行真正的選擇。如你所見,我正在緩存所有內容。我的問題是爲什麼這不起作用。 症狀:從依賴跟蹤器回調被調用兩次然後它阻止。我實現了這一點,因爲我的通知是在頁面刷新開始之後發佈的。我試圖通過手動重置事件來給通知一個機會,然後設置手動重置事件並刷新UI。正如我所說的,在經過兩次OnChange之後,它會凍結。我能做什麼? Dependency Tracker在Unity容器中實例註冊,Repository是類型註冊的。

+0

是否因爲存儲類型已註冊,未註冊實例?順便說一句,我確實在每個容器中設置了依賴關係跟蹤器的回調。 – DaeMoohn 2009-10-12 16:25:45

回答

6
void dependency_OnChange(object sender, SqlNotificationEventArgs e) 

您需要檢查SqlNotificationEventArgs並查看通知您,數據更改或其他內容。檢查InfoInsert/Update/Delete。檢查SourceData。檢查TypeChange

很有可能您的查詢被直接標記爲不符合restrictions imposed on Query Notifications。是的,我知道鏈接指向索引視圖,如果您想了解原因,請閱讀The Mysterious Notification

您的更新等待_ResetEvent和回調信號_ResetEvent之間也有一個競爭條件。 T1調用更新。同時在數據中發生無關更新並調用回調。 _ResetEvent已設置。 T1完成更新並等待_ResteEvent發出信號,然後繼續。調用者假設自己的更新發生回調並刷新緩存,但這不是事實。

第二個更嚴重的問題是在事務存在時代碼不正確。 UpdateXXX假定它自己更新的回調將會發生,並等待它。只有在Update提交之後,查詢通知纔會由引擎傳遞,因此當存在TransactionScope時,UpdateXXX方法將阻止等待通知,直到UpdateXXX返回(活動死鎖)纔會出現。

也不清楚TrackForChanges的目的是什麼。您正在讀取SqlDataReader(sqlCommand.ExecuteReader),但忽略結果。通過查詢通知您提交查詢,閱讀結果,當結果發生變化時您會收到通知。

最後,never read data in the SqlDependency notification callback

+0

1.與用於通知的查詢相關,它們如下所示:從dbo.table中選擇column1,column2,column3。 – DaeMoohn 2009-10-12 17:05:01

+0

0.感謝關於SqlNotificationEventArgs的提示。 – DaeMoohn 2009-10-12 17:06:44

+0

2.關於交易,我可以假設他們不會出現在這個應用程序中。但問題仍然存在,並感謝您指出。它並沒有跨越我的想法。 – DaeMoohn 2009-10-12 17:16:50