2011-12-22 13 views
12

मुझे पता नहीं लगा सकता कि HasChanged मेरे SqlCacheDependency ऑब्जेक्ट का मूल्य मूल रूप से कमांड निष्पादन से वापस आ रहा है, लेकिन डेटाबेस से वापस आने के लगभग तुरंत बाद, मूल्य सही हो जाता है।मेरा एसक्ल कैश पर निर्भरता क्यों गलत है, लेकिन परिवर्तन के बाद लगभग तुरंत?

कभी-कभी यह कैश में भी डालने से पहले होता है, जिससे कैश इसे तुरंत त्याग देता है, कभी-कभी यह डालने के बाद होता है, और मैं एक गणनाकर्ता पकड़ सकता हूं जो कैश में कुंजी देखता है लेकिन इससे पहले कि मैं लूप भी उस आइटम को कैश में हटा दिया गया है।

sproc:

ALTER PROCEDURE [dbo].[ntz_dal_ER_X_Note_SelectAllWER_ID] 
     @ER_ID int 
AS 
BEGIN 
    SELECT 
     ER_X_Note_ID, 
     ER_ID, 
     Note_ID 
    FROM dbo.ER_X_Note e 
    WHERE 
     ER_ID = @ER_ID 
END 

डेटाबेस एमएस एसक्यूएल सर्वर 2008, दलाल सेवा सक्षम है, और कुछ उत्पादन कैश करता है और कैश की गई रहते हैं। उदाहरण के लिए, यह एक बस ठीक काम करता है:

ALTER PROC [dbo].[ntz_dal_GetCacheControllerByEntityName] (
    @Name varchar(50) 
) AS 
BEGIN 
    SELECT 
     CacheController_ID, 
     EntityName, 
     CacheEnabled, 
     Expiration 
    From dbo.CacheController cc 
    WHERE EntityName = @Name 
END 

कोड जो सवाल में sproc कॉल विफल रहता है:

DataSet toReturn; 
    Hashtable paramHash = new Hashtable(); 
    paramHash.Add("ER_ID", _eR_ID.IsNull ? null : _eR_ID.Value.ToString()); 
    string cacheName = BuildCacheString("ntz_dal_ER_X_Note_SelectAllWER_ID", paramHash); 
    toReturn = (DataSet)GetFromCache(cacheName); 
    if (toReturn == null) 
    { 

     // Set up parameters (1 input and 0 output) 
     SqlParameter[] arParms = { 
       new SqlParameter("@ER_ID", _eR_ID), 
      }; 
     SqlCacheDependency scd; 

     // Execute query. 
     toReturn = _dbTransaction != null 
      ? _dbConnection.ExecuteDataset(_dbTransaction, "dbo.[ntz_dal_ER_X_Note_SelectAllWER_ID]", out scd, arParms) 
      : _dbConnection.ExecuteDataset("dbo.[ntz_dal_ER_X_Note_SelectAllWER_ID]", out scd, arParms); 

     AddToCache(cacheName, toReturn, scd); 
    } 

    return toReturn; 

कोड है कि काम करता है

 const string sprocName = "ntz_dal_GetCacheControllerByEntityName"; 
     string cacheControlPrefix = "CacheController_" + CachePrefix; 
     CacheControl controller = (CacheControl)_cache[cacheControlPrefix]; 
     if (controller == null) 
     { 
      try 
      { 
       SqlParameter[] arParms = { 
              new SqlParameter("@Name", CachePrefix), 
             }; 
       SqlCacheDependency sqlCacheDependency; 

       // Execute query. 
       DataSet result = _dbTransaction != null 
            ? _dbConnection.ExecuteDataset(_dbTransaction, sprocName, out sqlCacheDependency, arParms) 
            : _dbConnection.ExecuteDataset(sprocName, out sqlCacheDependency, arParms); 

       controller = result.Tables[0].Rows.Count == 0 
           ? new CacheControl(false) 
           : new CacheControl(result.Tables[0].Rows[0]); 

       _cache.Insert(cacheControlPrefix, controller, sqlCacheDependency); 
      } 
      catch (Exception ex) 
      { 
       // if sproc retreival fails cache the result of false so we don't keep trying 
       // this is the only case where it can be added with no expiration date 
       controller = new CacheControl(false); 

       // direct cache insert, no dependency, no expiration, never try again for this entity 
       if (HttpContext.Current != null && UseCaching && _cache != null) _cache.Insert(cacheControlPrefix, controller); 
      } 
     } 
     return controller; 

AddToCache विधि ओवरलोड हो गया है और इसमें अधिक परीक्षण हैं; कामकाजी विधि में प्रत्यक्ष _cache.Insert उन अन्य परीक्षणों को बाईपास करना है। कामकाजी कोड यह निर्धारित करने में मदद करता है कि क्या डीबी कैशिंग बिल्कुल होनी चाहिए।

आप देख सकते हैं कि जब "गैर काम कर रहे" डेटा शुरू में लिया गया है, सब ठीक है:

enter image description here

लेकिन उस बिंदु से परे कहीं यादृच्छिक, इस उदाहरण में, बस अगली विधि

में कदम

enter image description here

और फिर भी डेटा बिल्कुल बदल नहीं रहा है; मैं डेटाबेस का इस उदाहरण को छूने वाला अकेला हूं।

उत्तर

6

यह वास्तव में, वास्तव में सरल था, इतना आसान मैंने इसे पूरी तरह से अनदेखा किया।

इस लेख Creating a Query for Notification, जो मैं DID कई बार दस्त में, यह स्पष्ट रूप से कहा गया है:

सेट विकल्प सेटिंग्स

जब एक SELECT कथन एक अधिसूचना अनुरोध के तहत निष्पादित किया जाता है, कनेक्शन अनुरोध सबमिट करता है कि अनुरोध के पास कनेक्शन सेट के विकल्प निम्नानुसार होंगे:

ANSI_NULLS ON 
ANSI_PADDING ON 
ANSI_WARNINGS ON 
CONCAT_NULL_YIELDS_NULL ON 
QUOTED_IDENTIFIER ON 
NUMERIC_ROUNDABORT OFF 
ARITHABORT ON 

ठीक है, मैंने पढ़ा और फिर से पढ़ा और फिर से पढ़ा और फिर से पढ़ा, और मुझे अभी भी नहीं देखा कि ANSI_NULLS और QUOTED_IDENTIFIER दोनों "बंद" थे, चालू नहीं थे।

मेरा डेटासेट अब परिवर्तन के झूठे संकेतकों के बिना डेटा को कैशिंग और रखरखाव कर रहा है।

1

मुझे लगता है कि यह समस्या आपके _eR_ID के साथ है। मुझे लगता है कि आपको असफल प्रक्रिया में स्थानीय चर जोड़ने का प्रयास करना चाहिए जो _eR_ID के लिए असंभव मान का उपयोग करता है, जैसे -1। मुझे विश्वास नहीं है कि क्या होने जा रहा है जब नल शामिल हैं और मुझे लगता है कि यह आपकी समस्या का स्रोत हो सकता है।

यहाँ संशोधित संस्करण है कि मैं प्रयास करने की अनुशंसा है:

DataSet toReturn; 
Hashtable paramHash = new Hashtable(); 

int local_er_ID = eR_ID.IsNull ? -1 : _eR_ID.Value; 
paramHash.Add("ER_ID", local_eR_ID.ToString()); 

string cacheName = BuildCacheString("ntz_dal_ER_X_Note_SelectAllWER_ID", paramHash); 
toReturn = (DataSet)GetFromCache(cacheName); 
if (toReturn == null) 
{ 

    // Set up parameters (1 input and 0 output) 
    SqlParameter[] arParms = { 
      new SqlParameter("@ER_ID", local_eR_ID), 
     }; 
    SqlCacheDependency scd; 

    // Execute query. 
    toReturn = _dbTransaction != null 
     ? _dbConnection.ExecuteDataset(_dbTransaction, "dbo.[ntz_dal_ER_X_Note_SelectAllWER_ID]", out scd, arParms) 
     : _dbConnection.ExecuteDataset("dbo.[ntz_dal_ER_X_Note_SelectAllWER_ID]", out scd, arParms); 

    AddToCache(cacheName, toReturn, scd); 
} 

return toReturn; 

महत्वपूर्ण

ऊपर कोड बनाते समय मुझे लगता है कि मैं अपने समस्या के स्रोत की खोज की: जब संग्रहीत proc पैरामीटर , आप _eR_ID का उपयोग कर रहे हैं, लेकिन जब आप paramHash सेट करते हैं तो आप _eR_ID.Value का उपयोग कर रहे हैं।

कोड पुनर्लेख इस समस्या को हल करेगा, लेकिन मुझे संदेह है कि यह समस्या की जड़ है।

+0

मैं इसे आज़माउंगा, लेकिन मुझे लगता है कि यह असंभव है, क्योंकि परम हैश का उपयोग केवल उस कुंजी नाम को बनाने के लिए किया जाता है जिसके अंतर्गत कैश आइटम बनाया जाता है। –

+1

@TheEvilGreebo: क्षमा करें, मुझे नहीं लगता कि मैंने काफी अच्छी तरह से संवाद किया है। मुझे लगता है कि समस्या कोड की यह पंक्ति है 'नया एसक्यूएल पैरामीटर ("@ ईआर_आईडी", _eR_ID) '। यह पूरे _eR_ID ऑब्जेक्ट को पैरामीटर पर पास करता है और मुझे यकीन नहीं है कि यह एसक्यूएल के मान के लिए कैसे अनुवाद करता है (मुझे संदेह है कि यह ऑब्जेक्ट पर ToString() को कॉल करता है)। इससे पहले कोड में आप _eR_ID.Value का उपयोग करते हैं, इसलिए मुझे लगता है कि आपको आवश्यक न्यूनतम परिवर्तन 'नया एसक्यूएल पैरामीटर ("@ ER_ID", _eR_ID.Value) 'है। –

+0

ओह, मैं देखता हूं कि आपका क्या मतलब है। खैर _eR_ID एक SqlInt32 है - इसलिए कोई ऐसा सोचता है कि इसका उपयोग करके एक नया SqlParm प्रारंभ करना कोई समस्या नहीं पैदा करेगा, लेकिन इसकी कोशिश करने लायक है! –

0

एक ही समस्या में चल रहा है और बिना किसी सहायता के ऑनलाइन जवाब ढूंढ रहा है, मैं प्रोफाइलर से एक्सएमएल अमान्य सदस्यता प्रतिक्रिया को फिर से खोज रहा था।

मुझे msdn समर्थन साइट पर एक उदाहरण मिला जिसमें कोड का थोड़ा अलग क्रम था। जब मैंने कोशिश की तो मुझे समस्या का एहसास हुआ - कमांड ऑब्जेक्ट और कैश निर्भरता ऑब्जेक्ट बनाने के बाद तक अपनी कनेक्शन ऑब्जेक्ट न खोलें। यहाँ आपको पालन करना होगा और सब अच्छा हो जाएगा:

  1. सूचनाएं (SqlCahceDependencyAdmin) सक्षम करने के लिए और SqlDependency.Start पहले
  2. चलाने कनेक्शन वस्तु
  3. बनाएं आदेश वस्तु बना सकते हैं और आदेश आवंटित सुनिश्चित करें पाठ, प्रकार, और कनेक्शन ऑब्जेक्ट (रचनाकारों का कोई संयोजन, गुण सेट करना, या CreateCommand का उपयोग करना)।
  4. एसक्यूएल कैश निर्भरता वस्तु
  5. ओपन कनेक्शन वस्तु
  6. बनाएं निष्पादित क्वेरी
  7. आइटम निर्भरता का उपयोग कर कैश करने के लिए जोड़ें।

यदि आप इस आदेश का पालन करते हैं, और अपने चयन कथन पर अन्य सभी आवश्यकताओं का पालन करें, तो कोई अनुमति समस्या नहीं है, यह काम करेगा!

मेरा मानना ​​है कि समस्या को यह करना है कि .NET ढांचा कनेक्शन कैसे प्रबंधित करता है, विशेष रूप से कौन सी सेटिंग्स सेट की जाती हैं। मैंने इसे अपने एसक्यूएल कमांड टेस्ट में ओवरराइड करने की कोशिश की लेकिन यह कभी काम नहीं किया। यह केवल एक अनुमान है - मुझे पता है कि आदेश बदल रहा है तुरंत इस मुद्दे को हल किया।

मैं इसे निम्नलिखित से msdn पोस्ट में एक साथ टुकड़ा करने में सक्षम था।

यह पोस्ट अमान्य सदस्यता के अधिक सामान्य कारणों में से एक था, और यह दिखाता है कि .NET क्लाइंट उन गुणों को सेट करता है जो अधिसूचना की आवश्यकता के विपरीत हैं।

https://social.msdn.microsoft.com/Forums/en-US/cf3853f3-0ea1-41b9-987e-9922e5766066/changing-default-set-options-forced-by-net?forum=adodotnetdataproviders

तो इस पोस्ट के लिए उपयोगकर्ता के पास, मेरे जैसे, सरल प्रारूप करने के लिए अपने कोड को कम कर दिया था से था। मेरा मूल कोड पैटर्न उसके समान था।

https://social.technet.microsoft.com/Forums/windows/en-US/5a29d49b-8c2c-4fe8-b8de-d632a3f60f68/subscriptions-always-invalid-usual-suspects-checked-no-joy?forum=sqlservicebroker

तो मैं भी इस समस्या का एक बहुत ही सरल कमी इस पोस्ट पाया, केवल अपने एक सरल मुद्दा था - टेबल के लिए 2 हिस्सा नाम की जरूरत है। अपने मामले में सुझाव ने इस मुद्दे को हल किया। अपने कोड को देखने के बाद मैंने देखा कि मुख्य अंतर कमांड ऑब्जेक्ट के बाद कनेक्शन ऑब्जेक्ट खोलने का इंतजार कर रहा था और निर्भरता ऑब्जेक्ट बनाया गया था। मेरी एकमात्र धारणा हुड के नीचे है (मैंने अभी तक केवल एक धारणा की जांच करने के लिए परावर्तक शुरू नहीं किया है) कनेक्शन ऑब्जेक्ट अलग-अलग खोला गया है, या इस संगठन के कारण घटनाओं और आदेश का क्रम अलग-अलग होता है।

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/bc9ca094-a989-4403-82c6-7f608ed462ce/sql-server-not-creating-subscription-for-simple-select-query-when-using-sqlcachedependency?forum=sqlservicebroker

मुझे आशा है कि यह एक ऐसी ही अंक में किसी और में मदद करता है।

+0

मुझे नहीं लगता कि यह सही है। आदेश महत्वपूर्ण है हाँ, लेकिन जब आप कनेक्शन खोलते हैं तो afaik नहीं है। –

संबंधित मुद्दे