سؤال

أنا أستكشف إشعارات الاستعلام باستخدام SQLDependency فصل.من السهل بناء مثال عملي بسيط، لكني أشعر وكأنني أفتقد شيئًا ما.بمجرد أن أتخطى مثالًا بسيطًا لجدول واحد/تبعية واحدة، فإنني أتساءل كيف يمكنني معرفة التبعية التي أدت إلى رد الاتصال الخاص بي؟

أواجه بعض الصعوبة في الشرح، لذا قمت بتضمين المثال البسيط أدناه.متى AChange() يسمى لا أستطيع النظر إلى SQL داخل التبعية، وليس لدي إشارة إلى كائن ذاكرة التخزين المؤقت المرتبط.

إذن ما هو الصبي أن يفعل؟

  • الخيار 1 - قم بإنشاء وظيفة مميزة لكل كائن أريد تتبعه وقم بتشفير مفتاح ذاكرة التخزين المؤقت (أو المعلومات ذات الصلة) في رد الاتصال.يبدو هذا قذرًا ويزيل إمكانية إضافة عناصر ذاكرة تخزين مؤقت جديدة دون نشر كود جديد - ewww.
  • الخيار 2 - استخدم التبعية Id الملكية وهيكل التتبع الموازي

هل أنا فقط في عداد المفقودين شيئا؟فهل هذا نقص في SQLDependency بناء؟لقد ألقيت نظرة على 20 مقالة مختلفة حول هذا الموضوع ويبدو أن جميعهم لديهم نفس الفجوة.اقتراحات؟

نموذج التعليمات البرمجية

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
   }
}
هل كانت مفيدة؟

المحلول

اولا في المقام الاول اولا قبل كل شي:يجب إعداد المعالج قبل يتم تنفيذ الأمر:

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

وإلا فستكون لديك نافذة قد يتم فيها فقدان الإشعار ولن يتم استدعاء رد الاتصال الخاص بك مطلقًا.

والآن بخصوص سؤالك:يجب عليك استخدام رد اتصال منفصل لكل استعلام.في حين أن هذا قد يبدو مرهقًا، إلا أنه في الواقع تافه باستخدام لامدا.شيء مثل ما يلي:

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();
...

وتذكر أن دائماً تحقق من مصدر الإشعارات والمعلومات والنوع.وإلا فإنك تخاطر بتدوير الغثيان عندما يتم إخطارك لأسباب آخر من تغيير البيانات، مثل استعلام غير صالح.كتعليق جانبي، أود أن أضيف أن التصميم الجيد لذاكرة التخزين المؤقت لا يؤدي إلى تحديث ذاكرة التخزين المؤقت عند إبطالها، ولكنه ببساطة يبطل صلاحية العنصر المخزن مؤقتًا ويتيح الطلب التالي في الواقع جلب عنصر جديد.من خلال النهج "الاستباقي" الذي تتبعه، يمكنك تحديث العناصر المخزنة مؤقتًا حتى عند عدم الحاجة إليها، والتحديث عدة مرات قبل الوصول إليها وما إلى ذلك.لقد استبعدت من المثال معالجة الأخطاء والمزامنة الصحيحة لمؤشر الترابط (كلاهما مطلوب).

وأخيرا، إلقاء نظرة على LinqtoCache وهو ما يفعل إلى حد كبير ما تحاول القيام به، ولكن بالنسبة لاستعلامات LINQ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top