2011-12-22 31 views
12

我不知道爲什麼SqlCacheDependency對象的HasChanged值最初從命令執行返回爲false,但在數據從數據庫返回後幾乎立即返回,值更改爲true。爲什麼我的SqlCacheDependency HasChanged會變回false,但在更改爲true後幾乎立即變爲false?

有時甚至在項目被插入到緩存之前發生,導致緩存立即丟棄它,有時候是在插入之後,我可以獲取一個枚舉器,它在緩存中但是在我循環到該項目在緩存中已被刪除。

存儲過程:

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 

的數據庫是MS SQL Server 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 

它調用存儲過程中的問題,失敗的代碼:

,工程

 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方法重載,

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; 

代碼有更多的測試;工作方法中的直接_cache.Insert是繞過其他測試。工作代碼有助於確定數據庫緩存是否應該發生。

你可以看到,當「非工作」的數據最初檢索,一切都OK:

enter image description here

而是介於隨機超出該點,在這種情況下,剛剛步入下一個方法

enter image description here

然而數據並沒有改變;我是唯一一個接觸這個數據庫實例的人。

回答

6

這真的很簡單,那麼簡單,我完全忽略了它。

在這篇文章中Creating a Query for Notification,我DID沖刷多次,它明確規定:

SET選項設置

當SELECT語句下的通知要求執行,則 連接是提交請求必須有 連接集的選項如下:

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

那麼,我讀取並重新讀取並重新讀取sproc,並且我仍然沒有看到ANSI_NULLS和QUOTED_IDENTIFIER都是「OFF」,而不是ON。

我的數據集現在正確緩存和保留數據,沒有錯誤的變化指標。

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; 

重要

在創建上面的代碼,我想我發現了你的問題的根源:設置存儲過程的參數時, ,您正在使用_eR_ID,但是當您設置paramHash時,您正在使用_eR_ID.Value

代碼重寫將解決這個問題,但我懷疑這是問題的根源。

+0

我會試試它,但我認爲這不太可能,因爲param哈希僅用於構建創建緩存項的密鑰名稱。 – 2011-12-27 00:38:39

+1

@TheEvilGreebo:對不起,我覺得我沒有足夠的溝通。我認爲問題是這行代碼'新的SqlParameter(「@ ER_ID」,_eR_ID)'。這將整個_eR_ID對象傳遞給參數,我不確定它是如何將它轉換爲Sql的值(我懷疑它在對象上調用了ToString())。之前在代碼中使用_eR_ID.Value,所以我認爲您需要的最小更改是'new SqlParameter(「@ ER_ID」,_eR_ID.Value)'。 – 2011-12-27 00:51:58

+0

哦,我明白你的意思了。那麼_eR_ID是一個SqlInt32 - 所以人們會認爲使用它初始化一個新的SqlParm不會引起問題,但它值得一試! – 2011-12-27 01:47:51

0

在沒有任何幫助的情況下,遇到同樣的問題並在網上找到相同的答案,我正在重新研究探查器的xml無效訂閱響應。

我在msdn支持網站上發現了一個具有略微不同代碼順序的示例。當我嘗試它時,我意識到了這個問題 - 直到創建命令對象和緩存依賴對象之後纔打開連接對象。這裏是你必須遵守的秩序,都將是不錯的:

  1. 確保啓用通知(SqlCahceDependencyAdmin)並運行SqlDependency.Start第一
  2. 創建連接對象
  3. 創建命令對象,並指定命令文本,類型和連接對象(構造函數的任意組合,設置屬性或使用CreateCommand)。
  4. 創建SQL緩存依賴對象
  5. 打開連接對象
  6. 執行查詢
  7. 添加項目使用依賴緩存。

如果您按照此順序,並按照您的select語句的所有其他要求,不要有任何權限問題,這將工作!

我認爲這個問題與.NET框架如何管理連接有關,特別是設置了什麼設置。我嘗試覆蓋這在我的SQL命令測試,但它從來沒有奏效。這只是一個猜測 - 我所知道的是改變立即解決問題的順序。

我可以將它從下面的文件拼湊到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部分名稱表。在他的情況下,這個建議解決了這個問題。在查看他的代碼後,我注意到主要區別在於等待打開連接對象,直到命令對象和依賴對象創建後。我唯一的假設是隱藏的(我還沒有開始反射器檢查,所以只有一個假設),Connection對象以不同的方式打開,或者事件和命令的順序發生不同,因爲這種關聯。

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

我不認爲這是正確的。順序是重要的,但打開連接時不是。 – 2014-12-13 14:44:45

相關問題