Frage

Ich untersuche Abfragebenachrichtigungen mit dem SQLDependency Klasse.Das Erstellen eines einfachen Arbeitsbeispiels ist einfach, aber ich habe das Gefühl, dass mir etwas fehlt.Sobald ich an einem einfachen Beispiel für eine Tabelle / eine Abhängigkeit vorbeigehe, wundere ich mich wie kann ich herausfinden, welche Abhängigkeit meinen Rückruf ausgelöst hat?

Ich habe ein bisschen Mühe zu erklären, also habe ich das einfache Beispiel unten eingefügt.Wenn AChange() aufgerufen wird, kann ich die SQL in der Abhängigkeit nicht anzeigen und ich habe keinen Verweis auf das zugehörige Cache-Objekt.

Also, was soll ein Junge tun?

  • Möglichkeit 1 - erstellen Sie für jedes Objekt, das ich verfolgen möchte, eine eigene Funktion und codieren Sie den Cache-Schlüssel (oder relevante Informationen) im Rückruf fest.Dies fühlt sich schmutzig an und beseitigt die Möglichkeit, neue Cache-Elemente hinzuzufügen, ohne neuen Code bereitzustellen - ewww.
  • Möglichkeit 2 - Verwenden Sie die Abhängigkeit Id eigenschaft und eine parallele Verfolgungsstruktur

Vermisse ich einfach etwas?Ist das ein Mangel in der SQLDependency struktur?Ich habe mir 20 verschiedene Artikel zu diesem Thema angesehen und alle scheinen das gleiche Loch zu haben.Vorschläge?

Codebeispiel

public class DependencyCache{
   public static  string       cacheName  = "Client1";
   public static  MemoryCache  memCache   = new MemoryCache(cacheName);

   public DependencyCache() {
      SqlDependency.Start(connString);
   }

   private static string GetSQL() {
      return "select  someString FROM dbo.TestTable";
   }

   public void DoTest() {
      if (memCache["TEST_KEY"] != null ) {
         Debug.WriteLine("resources found in cache");
         return;
      }
      Cache_GetData();
   }

   private void Cache_GetData() {
      SqlConnection         oConn;
      SqlCommand            oCmd;
      SqlDependency         oDep;
      SqlDataReader         oRS;
      List<string>          stuff    = new List<string>();
      CacheItemPolicy       policy   = new CacheItemPolicy();

      SqlDependency.Start(connString);
      using (oConn = new SqlConnection(connString) ) {
         using (oCmd = new SqlCommand(GetSQL(), oConn) ) {
            oDep = new SqlDependency(oCmd);
            oConn.Open();
            oRS = oCmd.ExecuteReader();

            while(oRS.Read() ) {
                  resources.Add( oRS.GetString(0) );
            }

            oDep.OnChange += new OnChangeEventHandler (AChange);
         }
      }
      memCache.Set("TEST_KEY", stuff, policy);
   }

   private void AChange(  object sender, SqlNotificationEventArgs e) {
      string msg= "Dependency Change \nINFO: {0} : SOURCE {1} :TYPE: {2}";
      Debug.WriteLine(String.Format(msg, e.Info, e.Source, e.Type));

      // If multiple queries use this as a callback how can i figure 
      // out WHAT QUERY TRIGGERED the change?
      // I can't figure out how to tell multiple dependency objects apart

      ((SqlDependency)sender).OnChange -= Cache_SqlDependency_OnChange; 
      Cache_GetData(); //reload data
   }
}
War es hilfreich?

Lösung

Zuallererst:der Handler muss eingerichtet sein vor der Befehl wird ausgeführt:

 oDep = new SqlDependency(oCmd);
 oConn.Open();
 oDep.OnChange += new OnChangeEventHandler (AChange);
 oRS = oCmd.ExecuteReader();
 while(oRS.Read() ) {
     resources.Add( oRS.GetString(0) );
 }

Andernfalls haben Sie ein Fenster, in dem die Benachrichtigung verloren gehen kann und Ihr Rückruf nie aufgerufen wird.

Nun zu deiner Frage:sie sollten für jede Abfrage einen separaten Rückruf verwenden.Während dies umständlich erscheinen mag, ist es durch die Verwendung eines Lambdas eigentlich trivial.So etwas wie das Folgende:

oDep = new SqlDependency(oCmd);
oConn.Open();
oDep.OnChange += (sender, e) =>
{
   string msg = "Dependency Change \nINFO: {0} : SOURCE {1} :TYPE: {2}";
   Debug.WriteLine(String.Format(msg, e.Info, e.Source, e.Type));

   // The command that trigger the notification is captured in the context:
   //  is oCmd
   //
   // You can now call a handler passing in the relevant info:
   //
   Reload_Data(oCmd, ...);
};
oRS = oCmd.ExecuteReader();
...

Und denken Sie daran immer überprüfen Sie die Benachrichtigungsquelle, die Informationen und den Typ.Andernfalls laufen Sie Gefahr, sich bis zum Überdruss zu drehen, wenn Sie aus Gründen benachrichtigt werden andere als Datenänderung, wie ungültige Abfrage.Als Nebenkommentar möchte ich hinzufügen, dass ein gutes Cache-Design den Cache bei der Ungültigmachung nicht aktualisiert, sondern einfach das zwischengespeicherte Element ungültig macht und das nächste Anfrage tatsächlich einen frischen Gegenstand holen.Mit Ihrem 'proaktiven' Ansatz aktualisieren Sie zwischengespeicherte Elemente, auch wenn sie nicht benötigt werden, aktualisieren Sie mehrmals, bevor auf sie zugegriffen wird usw. usw.Ich habe aus dem Beispiel die Fehlerbehandlung und die ordnungsgemäße Thread-Synchronisation ausgelassen (beide erforderlich).

Zum Schluss schauen Sie sich an LinqtoCache das macht so ziemlich das, was Sie versuchen, aber für LINQ-Abfragen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top